rrce-workflow 0.2.35 → 0.2.36
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 +668 -517
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -935,6 +935,10 @@ function parseMCPConfig(content) {
|
|
|
935
935
|
continue;
|
|
936
936
|
}
|
|
937
937
|
if (currentProject) {
|
|
938
|
+
const pathMatch = trimmed.match(/^path:\s*["']?([^"'\n]+)["']?/);
|
|
939
|
+
if (pathMatch) {
|
|
940
|
+
currentProject.path = pathMatch[1].trim();
|
|
941
|
+
}
|
|
938
942
|
const exposeMatch = trimmed.match(/^expose:\s*(true|false)/);
|
|
939
943
|
if (exposeMatch) {
|
|
940
944
|
currentProject.expose = exposeMatch[1] === "true";
|
|
@@ -981,7 +985,12 @@ projects:
|
|
|
981
985
|
} else {
|
|
982
986
|
for (const project of config.projects) {
|
|
983
987
|
content += ` - name: "${project.name}"
|
|
984
|
-
|
|
988
|
+
`;
|
|
989
|
+
if (project.path) {
|
|
990
|
+
content += ` path: "${project.path}"
|
|
991
|
+
`;
|
|
992
|
+
}
|
|
993
|
+
content += ` expose: ${project.expose}
|
|
985
994
|
permissions:
|
|
986
995
|
knowledge: ${project.permissions.knowledge}
|
|
987
996
|
tasks: ${project.permissions.tasks}
|
|
@@ -991,16 +1000,31 @@ projects:
|
|
|
991
1000
|
}
|
|
992
1001
|
return content;
|
|
993
1002
|
}
|
|
994
|
-
function setProjectConfig(config, name, expose, permissions) {
|
|
995
|
-
|
|
1003
|
+
function setProjectConfig(config, name, expose, permissions, projectPath) {
|
|
1004
|
+
let existing = config.projects.find((p) => {
|
|
1005
|
+
if (projectPath && p.path) {
|
|
1006
|
+
return p.path === projectPath;
|
|
1007
|
+
}
|
|
1008
|
+
if (!projectPath && !p.path) {
|
|
1009
|
+
return p.name === name;
|
|
1010
|
+
}
|
|
1011
|
+
if (projectPath && !p.path && p.name === name) {
|
|
1012
|
+
return true;
|
|
1013
|
+
}
|
|
1014
|
+
return false;
|
|
1015
|
+
});
|
|
996
1016
|
if (existing) {
|
|
997
1017
|
existing.expose = expose;
|
|
1018
|
+
if (projectPath && !existing.path) {
|
|
1019
|
+
existing.path = projectPath;
|
|
1020
|
+
}
|
|
998
1021
|
if (permissions) {
|
|
999
1022
|
existing.permissions = { ...existing.permissions, ...permissions };
|
|
1000
1023
|
}
|
|
1001
1024
|
} else {
|
|
1002
1025
|
config.projects.push({
|
|
1003
1026
|
name,
|
|
1027
|
+
path: projectPath,
|
|
1004
1028
|
expose,
|
|
1005
1029
|
permissions: permissions ? { ...DEFAULT_PERMISSIONS, ...permissions } : { ...DEFAULT_PERMISSIONS }
|
|
1006
1030
|
});
|
|
@@ -1011,15 +1035,25 @@ function removeProjectConfig(config, name) {
|
|
|
1011
1035
|
config.projects = config.projects.filter((p) => p.name !== name);
|
|
1012
1036
|
return config;
|
|
1013
1037
|
}
|
|
1014
|
-
function isProjectExposed(config, name) {
|
|
1015
|
-
const project = config.projects.find((p) =>
|
|
1038
|
+
function isProjectExposed(config, name, projectPath) {
|
|
1039
|
+
const project = config.projects.find((p) => {
|
|
1040
|
+
if (projectPath && p.path) return p.path === projectPath;
|
|
1041
|
+
if (!projectPath && !p.path) return p.name === name;
|
|
1042
|
+
if (projectPath && !p.path) return p.name === name;
|
|
1043
|
+
return false;
|
|
1044
|
+
});
|
|
1016
1045
|
if (project) {
|
|
1017
1046
|
return project.expose;
|
|
1018
1047
|
}
|
|
1019
1048
|
return config.defaults.includeNew;
|
|
1020
1049
|
}
|
|
1021
|
-
function getProjectPermissions(config, name) {
|
|
1022
|
-
const project = config.projects.find((p) =>
|
|
1050
|
+
function getProjectPermissions(config, name, projectPath) {
|
|
1051
|
+
const project = config.projects.find((p) => {
|
|
1052
|
+
if (projectPath && p.path) return p.path === projectPath;
|
|
1053
|
+
if (!projectPath && !p.path) return p.name === name;
|
|
1054
|
+
if (projectPath && !p.path) return p.name === name;
|
|
1055
|
+
return false;
|
|
1056
|
+
});
|
|
1023
1057
|
return project?.permissions ?? config.defaults.permissions;
|
|
1024
1058
|
}
|
|
1025
1059
|
var init_config = __esm({
|
|
@@ -1031,11 +1065,6 @@ var init_config = __esm({
|
|
|
1031
1065
|
});
|
|
1032
1066
|
|
|
1033
1067
|
// src/mcp/logger.ts
|
|
1034
|
-
var logger_exports = {};
|
|
1035
|
-
__export(logger_exports, {
|
|
1036
|
-
getLogFilePath: () => getLogFilePath,
|
|
1037
|
-
logger: () => logger
|
|
1038
|
-
});
|
|
1039
1068
|
import * as fs8 from "fs";
|
|
1040
1069
|
import * as path9 from "path";
|
|
1041
1070
|
function getLogFilePath() {
|
|
@@ -1105,7 +1134,7 @@ import * as path10 from "path";
|
|
|
1105
1134
|
function getExposedProjects() {
|
|
1106
1135
|
const config = loadMCPConfig();
|
|
1107
1136
|
const allProjects = scanForProjects();
|
|
1108
|
-
return allProjects.filter((project) => isProjectExposed(config, project.name));
|
|
1137
|
+
return allProjects.filter((project) => isProjectExposed(config, project.name, project.dataPath));
|
|
1109
1138
|
}
|
|
1110
1139
|
function detectActiveProject() {
|
|
1111
1140
|
const exposed = getExposedProjects();
|
|
@@ -1116,16 +1145,16 @@ function detectActiveProject() {
|
|
|
1116
1145
|
}
|
|
1117
1146
|
function getProjectContext(projectName) {
|
|
1118
1147
|
const config = loadMCPConfig();
|
|
1119
|
-
|
|
1148
|
+
const projects = scanForProjects();
|
|
1149
|
+
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
|
|
1150
|
+
if (!project) {
|
|
1120
1151
|
return null;
|
|
1121
1152
|
}
|
|
1122
|
-
const permissions = getProjectPermissions(config, projectName);
|
|
1153
|
+
const permissions = getProjectPermissions(config, projectName, project.dataPath);
|
|
1123
1154
|
if (!permissions.knowledge) {
|
|
1124
1155
|
return null;
|
|
1125
1156
|
}
|
|
1126
|
-
|
|
1127
|
-
const project = projects.find((p) => p.name === projectName);
|
|
1128
|
-
if (!project?.knowledgePath) {
|
|
1157
|
+
if (!project.knowledgePath) {
|
|
1129
1158
|
return null;
|
|
1130
1159
|
}
|
|
1131
1160
|
const contextPath = path10.join(project.knowledgePath, "project-context.md");
|
|
@@ -1136,16 +1165,16 @@ function getProjectContext(projectName) {
|
|
|
1136
1165
|
}
|
|
1137
1166
|
function getProjectTasks(projectName) {
|
|
1138
1167
|
const config = loadMCPConfig();
|
|
1139
|
-
|
|
1168
|
+
const projects = scanForProjects();
|
|
1169
|
+
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
|
|
1170
|
+
if (!project) {
|
|
1140
1171
|
return [];
|
|
1141
1172
|
}
|
|
1142
|
-
const permissions = getProjectPermissions(config, projectName);
|
|
1173
|
+
const permissions = getProjectPermissions(config, projectName, project.dataPath);
|
|
1143
1174
|
if (!permissions.tasks) {
|
|
1144
1175
|
return [];
|
|
1145
1176
|
}
|
|
1146
|
-
|
|
1147
|
-
const project = projects.find((p) => p.name === projectName);
|
|
1148
|
-
if (!project?.tasksPath || !fs9.existsSync(project.tasksPath)) {
|
|
1177
|
+
if (!project.tasksPath || !fs9.existsSync(project.tasksPath)) {
|
|
1149
1178
|
return [];
|
|
1150
1179
|
}
|
|
1151
1180
|
const tasks = [];
|
|
@@ -1172,7 +1201,7 @@ function searchKnowledge(query) {
|
|
|
1172
1201
|
const results = [];
|
|
1173
1202
|
const queryLower = query.toLowerCase();
|
|
1174
1203
|
for (const project of projects) {
|
|
1175
|
-
const permissions = getProjectPermissions(config, project.name);
|
|
1204
|
+
const permissions = getProjectPermissions(config, project.name, project.dataPath);
|
|
1176
1205
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
1177
1206
|
try {
|
|
1178
1207
|
const files = fs9.readdirSync(project.knowledgePath);
|
|
@@ -1209,102 +1238,12 @@ var init_resources = __esm({
|
|
|
1209
1238
|
}
|
|
1210
1239
|
});
|
|
1211
1240
|
|
|
1212
|
-
// src/mcp/
|
|
1213
|
-
|
|
1214
|
-
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
1215
|
-
return prompts.map((p) => {
|
|
1216
|
-
const args = [];
|
|
1217
|
-
if (p.frontmatter["required-args"]) {
|
|
1218
|
-
args.push(...p.frontmatter["required-args"].map((a) => ({
|
|
1219
|
-
name: a.name,
|
|
1220
|
-
description: a.prompt || a.name,
|
|
1221
|
-
required: true
|
|
1222
|
-
})));
|
|
1223
|
-
}
|
|
1224
|
-
if (p.frontmatter["optional-args"]) {
|
|
1225
|
-
args.push(...p.frontmatter["optional-args"].map((a) => ({
|
|
1226
|
-
name: a.name,
|
|
1227
|
-
description: a.prompt || a.name,
|
|
1228
|
-
required: false
|
|
1229
|
-
})));
|
|
1230
|
-
}
|
|
1231
|
-
return {
|
|
1232
|
-
name: p.frontmatter.name,
|
|
1233
|
-
description: p.frontmatter.description,
|
|
1234
|
-
arguments: args,
|
|
1235
|
-
content: p.content
|
|
1236
|
-
};
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
function getPromptDef(name) {
|
|
1240
|
-
return getAllPrompts().find((p) => p.name === name);
|
|
1241
|
-
}
|
|
1242
|
-
function renderPrompt(content, args) {
|
|
1243
|
-
let rendered = content;
|
|
1244
|
-
for (const [key, val] of Object.entries(args)) {
|
|
1245
|
-
rendered = rendered.replace(new RegExp(`{{${key}}}`, "g"), val);
|
|
1246
|
-
}
|
|
1247
|
-
return rendered;
|
|
1248
|
-
}
|
|
1249
|
-
var init_prompts2 = __esm({
|
|
1250
|
-
"src/mcp/prompts.ts"() {
|
|
1251
|
-
"use strict";
|
|
1252
|
-
init_prompts();
|
|
1253
|
-
}
|
|
1254
|
-
});
|
|
1255
|
-
|
|
1256
|
-
// src/mcp/server.ts
|
|
1257
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
1258
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1241
|
+
// src/mcp/handlers/resources.ts
|
|
1242
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
1259
1243
|
import {
|
|
1260
|
-
CallToolRequestSchema,
|
|
1261
1244
|
ListResourcesRequestSchema,
|
|
1262
|
-
|
|
1263
|
-
ReadResourceRequestSchema,
|
|
1264
|
-
ListPromptsRequestSchema,
|
|
1265
|
-
GetPromptRequestSchema
|
|
1245
|
+
ReadResourceRequestSchema
|
|
1266
1246
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
1267
|
-
async function startMCPServer(options = {}) {
|
|
1268
|
-
try {
|
|
1269
|
-
logger.info("Starting MCP Server...");
|
|
1270
|
-
process.on("uncaughtException", (error) => {
|
|
1271
|
-
logger.error("Uncaught Exception", error);
|
|
1272
|
-
console.error("Uncaught Exception:", error);
|
|
1273
|
-
});
|
|
1274
|
-
process.on("unhandledRejection", (reason) => {
|
|
1275
|
-
logger.error("Unhandled Rejection", reason);
|
|
1276
|
-
console.error("Unhandled Rejection:", reason);
|
|
1277
|
-
});
|
|
1278
|
-
const config = loadMCPConfig();
|
|
1279
|
-
mcpServer = new Server(
|
|
1280
|
-
{ name: "rrce-mcp-hub", version: "1.0.0" },
|
|
1281
|
-
{ capabilities: { resources: {}, tools: {}, prompts: {} } }
|
|
1282
|
-
);
|
|
1283
|
-
mcpServer.onerror = (error) => {
|
|
1284
|
-
logger.error("MCP Server Error", error);
|
|
1285
|
-
};
|
|
1286
|
-
registerResourceHandlers(mcpServer);
|
|
1287
|
-
registerToolHandlers(mcpServer);
|
|
1288
|
-
registerPromptHandlers(mcpServer);
|
|
1289
|
-
if (!options.interactive) {
|
|
1290
|
-
const transport = new StdioServerTransport();
|
|
1291
|
-
await mcpServer.connect(transport);
|
|
1292
|
-
} else {
|
|
1293
|
-
logger.info("Running in interactive mode (Stdio transport detached)");
|
|
1294
|
-
}
|
|
1295
|
-
serverState = { running: true, port: config.server.port, pid: process.pid };
|
|
1296
|
-
const exposed = getExposedProjects().map((p) => p.name).join(", ");
|
|
1297
|
-
logger.info(`RRCE MCP Hub started (pid: ${process.pid})`, { exposedProjects: exposed });
|
|
1298
|
-
if (!options.interactive) {
|
|
1299
|
-
console.error(`RRCE MCP Hub started (pid: ${process.pid})`);
|
|
1300
|
-
console.error(`Exposed projects: ${exposed}`);
|
|
1301
|
-
}
|
|
1302
|
-
return { port: config.server.port, pid: process.pid };
|
|
1303
|
-
} catch (error) {
|
|
1304
|
-
logger.error("Failed to start MCP server", error);
|
|
1305
|
-
throw error;
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
1247
|
function registerResourceHandlers(server) {
|
|
1309
1248
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
1310
1249
|
logger.debug("Listing resources");
|
|
@@ -1318,7 +1257,7 @@ function registerResourceHandlers(server) {
|
|
|
1318
1257
|
});
|
|
1319
1258
|
for (const project of projects) {
|
|
1320
1259
|
const config = loadMCPConfig();
|
|
1321
|
-
const permissions = getProjectPermissions(config, project.name);
|
|
1260
|
+
const permissions = getProjectPermissions(config, project.name, project.dataPath);
|
|
1322
1261
|
if (permissions.knowledge) {
|
|
1323
1262
|
resources.push({
|
|
1324
1263
|
uri: `rrce://projects/${project.name}/context`,
|
|
@@ -1373,6 +1312,65 @@ function registerResourceHandlers(server) {
|
|
|
1373
1312
|
}
|
|
1374
1313
|
});
|
|
1375
1314
|
}
|
|
1315
|
+
var init_resources2 = __esm({
|
|
1316
|
+
"src/mcp/handlers/resources.ts"() {
|
|
1317
|
+
"use strict";
|
|
1318
|
+
init_logger();
|
|
1319
|
+
init_config();
|
|
1320
|
+
init_resources();
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
// src/mcp/prompts.ts
|
|
1325
|
+
function getAllPrompts() {
|
|
1326
|
+
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
1327
|
+
return prompts.map((p) => {
|
|
1328
|
+
const args = [];
|
|
1329
|
+
if (p.frontmatter["required-args"]) {
|
|
1330
|
+
args.push(...p.frontmatter["required-args"].map((a) => ({
|
|
1331
|
+
name: a.name,
|
|
1332
|
+
description: a.prompt || a.name,
|
|
1333
|
+
required: true
|
|
1334
|
+
})));
|
|
1335
|
+
}
|
|
1336
|
+
if (p.frontmatter["optional-args"]) {
|
|
1337
|
+
args.push(...p.frontmatter["optional-args"].map((a) => ({
|
|
1338
|
+
name: a.name,
|
|
1339
|
+
description: a.prompt || a.name,
|
|
1340
|
+
required: false
|
|
1341
|
+
})));
|
|
1342
|
+
}
|
|
1343
|
+
return {
|
|
1344
|
+
name: p.frontmatter.name,
|
|
1345
|
+
description: p.frontmatter.description,
|
|
1346
|
+
arguments: args,
|
|
1347
|
+
content: p.content
|
|
1348
|
+
};
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
function getPromptDef(name) {
|
|
1352
|
+
return getAllPrompts().find((p) => p.name === name);
|
|
1353
|
+
}
|
|
1354
|
+
function renderPrompt(content, args) {
|
|
1355
|
+
let rendered = content;
|
|
1356
|
+
for (const [key, val] of Object.entries(args)) {
|
|
1357
|
+
rendered = rendered.replace(new RegExp(`{{${key}}}`, "g"), val);
|
|
1358
|
+
}
|
|
1359
|
+
return rendered;
|
|
1360
|
+
}
|
|
1361
|
+
var init_prompts2 = __esm({
|
|
1362
|
+
"src/mcp/prompts.ts"() {
|
|
1363
|
+
"use strict";
|
|
1364
|
+
init_prompts();
|
|
1365
|
+
}
|
|
1366
|
+
});
|
|
1367
|
+
|
|
1368
|
+
// src/mcp/handlers/tools.ts
|
|
1369
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
1370
|
+
import {
|
|
1371
|
+
ListToolsRequestSchema,
|
|
1372
|
+
CallToolRequestSchema
|
|
1373
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
1376
1374
|
function registerToolHandlers(server) {
|
|
1377
1375
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
1378
1376
|
const tools = [
|
|
@@ -1525,6 +1523,21 @@ To fix this:
|
|
|
1525
1523
|
}
|
|
1526
1524
|
});
|
|
1527
1525
|
}
|
|
1526
|
+
var init_tools = __esm({
|
|
1527
|
+
"src/mcp/handlers/tools.ts"() {
|
|
1528
|
+
"use strict";
|
|
1529
|
+
init_logger();
|
|
1530
|
+
init_resources();
|
|
1531
|
+
init_prompts2();
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
|
|
1535
|
+
// src/mcp/handlers/prompts.ts
|
|
1536
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
1537
|
+
import {
|
|
1538
|
+
ListPromptsRequestSchema,
|
|
1539
|
+
GetPromptRequestSchema
|
|
1540
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
1528
1541
|
function registerPromptHandlers(server) {
|
|
1529
1542
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
1530
1543
|
logger.debug("Listing prompts");
|
|
@@ -1606,6 +1619,65 @@ Note: If the user's request refers to a project not listed here, ask them to exp
|
|
|
1606
1619
|
}
|
|
1607
1620
|
});
|
|
1608
1621
|
}
|
|
1622
|
+
var init_prompts3 = __esm({
|
|
1623
|
+
"src/mcp/handlers/prompts.ts"() {
|
|
1624
|
+
"use strict";
|
|
1625
|
+
init_logger();
|
|
1626
|
+
init_resources();
|
|
1627
|
+
init_prompts2();
|
|
1628
|
+
}
|
|
1629
|
+
});
|
|
1630
|
+
|
|
1631
|
+
// src/mcp/server.ts
|
|
1632
|
+
var server_exports = {};
|
|
1633
|
+
__export(server_exports, {
|
|
1634
|
+
getMCPServerStatus: () => getMCPServerStatus,
|
|
1635
|
+
startMCPServer: () => startMCPServer,
|
|
1636
|
+
stopMCPServer: () => stopMCPServer
|
|
1637
|
+
});
|
|
1638
|
+
import { Server as Server4 } from "@modelcontextprotocol/sdk/server/index.js";
|
|
1639
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1640
|
+
async function startMCPServer(options = {}) {
|
|
1641
|
+
try {
|
|
1642
|
+
logger.info("Starting MCP Server...");
|
|
1643
|
+
process.on("uncaughtException", (error) => {
|
|
1644
|
+
logger.error("Uncaught Exception", error);
|
|
1645
|
+
console.error("Uncaught Exception:", error);
|
|
1646
|
+
});
|
|
1647
|
+
process.on("unhandledRejection", (reason) => {
|
|
1648
|
+
logger.error("Unhandled Rejection", reason);
|
|
1649
|
+
console.error("Unhandled Rejection:", reason);
|
|
1650
|
+
});
|
|
1651
|
+
const config = loadMCPConfig();
|
|
1652
|
+
mcpServer = new Server4(
|
|
1653
|
+
{ name: "rrce-mcp-hub", version: "1.0.0" },
|
|
1654
|
+
{ capabilities: { resources: {}, tools: {}, prompts: {} } }
|
|
1655
|
+
);
|
|
1656
|
+
mcpServer.onerror = (error) => {
|
|
1657
|
+
logger.error("MCP Server Error", error);
|
|
1658
|
+
};
|
|
1659
|
+
registerResourceHandlers(mcpServer);
|
|
1660
|
+
registerToolHandlers(mcpServer);
|
|
1661
|
+
registerPromptHandlers(mcpServer);
|
|
1662
|
+
if (!options.interactive) {
|
|
1663
|
+
const transport = new StdioServerTransport();
|
|
1664
|
+
await mcpServer.connect(transport);
|
|
1665
|
+
} else {
|
|
1666
|
+
logger.info("Running in interactive mode (Stdio transport detached)");
|
|
1667
|
+
}
|
|
1668
|
+
serverState = { running: true, port: config.server.port, pid: process.pid };
|
|
1669
|
+
const exposed = getExposedProjects().map((p) => p.name).join(", ");
|
|
1670
|
+
logger.info(`RRCE MCP Hub started (pid: ${process.pid})`, { exposedProjects: exposed });
|
|
1671
|
+
if (!options.interactive) {
|
|
1672
|
+
console.error(`RRCE MCP Hub started (pid: ${process.pid})`);
|
|
1673
|
+
console.error(`Exposed projects: ${exposed}`);
|
|
1674
|
+
}
|
|
1675
|
+
return { port: config.server.port, pid: process.pid };
|
|
1676
|
+
} catch (error) {
|
|
1677
|
+
logger.error("Failed to start MCP server", error);
|
|
1678
|
+
throw error;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1609
1681
|
function stopMCPServer() {
|
|
1610
1682
|
if (mcpServer) {
|
|
1611
1683
|
logger.info("Stopping MCP Server...");
|
|
@@ -1625,8 +1697,9 @@ var init_server = __esm({
|
|
|
1625
1697
|
init_logger();
|
|
1626
1698
|
init_config();
|
|
1627
1699
|
init_resources();
|
|
1628
|
-
|
|
1629
|
-
|
|
1700
|
+
init_resources2();
|
|
1701
|
+
init_tools();
|
|
1702
|
+
init_prompts3();
|
|
1630
1703
|
serverState = { running: false };
|
|
1631
1704
|
mcpServer = null;
|
|
1632
1705
|
}
|
|
@@ -1820,28 +1893,190 @@ var init_install = __esm({
|
|
|
1820
1893
|
}
|
|
1821
1894
|
});
|
|
1822
1895
|
|
|
1823
|
-
// src/mcp/
|
|
1824
|
-
import "
|
|
1825
|
-
import
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1896
|
+
// src/mcp/commands/configure.ts
|
|
1897
|
+
import { spinner, note as note2, multiselect, isCancel as isCancel2 } from "@clack/prompts";
|
|
1898
|
+
import pc3 from "picocolors";
|
|
1899
|
+
async function handleConfigure() {
|
|
1900
|
+
const s = spinner();
|
|
1901
|
+
s.start("Scanning for projects...");
|
|
1902
|
+
const config = loadMCPConfig();
|
|
1903
|
+
const projects = scanForProjects();
|
|
1904
|
+
logger.info("Configure: Loaded config", { projects: config.projects, defaultMode: config.defaults.includeNew });
|
|
1905
|
+
s.stop("Projects found");
|
|
1906
|
+
if (projects.length === 0) {
|
|
1907
|
+
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
1908
|
+
return;
|
|
1832
1909
|
}
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1910
|
+
const options = projects.map((project) => {
|
|
1911
|
+
const projectConfig = config.projects.find(
|
|
1912
|
+
(p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
|
|
1913
|
+
);
|
|
1914
|
+
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
1915
|
+
return {
|
|
1916
|
+
value: project.dataPath,
|
|
1917
|
+
// Use precise data path as unique identifier
|
|
1918
|
+
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
1919
|
+
hint: project.dataPath
|
|
1920
|
+
};
|
|
1921
|
+
});
|
|
1922
|
+
const currentlyExposed = projects.filter((p) => {
|
|
1923
|
+
const cfg = config.projects.find(
|
|
1924
|
+
(c) => c.path && c.path === p.dataPath || !c.path && c.name === p.name
|
|
1925
|
+
);
|
|
1926
|
+
return cfg?.expose ?? config.defaults.includeNew;
|
|
1927
|
+
}).map((p) => p.dataPath);
|
|
1928
|
+
const selected = await multiselect({
|
|
1929
|
+
message: "Select projects to expose via MCP:",
|
|
1930
|
+
options,
|
|
1931
|
+
initialValues: currentlyExposed,
|
|
1932
|
+
required: false
|
|
1933
|
+
});
|
|
1934
|
+
if (isCancel2(selected)) {
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
const selectedPaths = selected;
|
|
1938
|
+
logger.info("Configure: User selected projects by path", selectedPaths);
|
|
1939
|
+
for (const project of projects) {
|
|
1940
|
+
const shouldExpose = selectedPaths.includes(project.dataPath);
|
|
1941
|
+
setProjectConfig(config, project.name, shouldExpose, void 0, project.dataPath);
|
|
1942
|
+
}
|
|
1943
|
+
saveMCPConfig(config);
|
|
1944
|
+
logger.info("Configure: Config saved", config);
|
|
1945
|
+
const exposedCount = selectedPaths.length;
|
|
1946
|
+
note2(
|
|
1947
|
+
`${pc3.green("\u2713")} Configuration saved!
|
|
1948
|
+
|
|
1949
|
+
Exposed projects: ${exposedCount}
|
|
1950
|
+
Hidden projects: ${projects.length - exposedCount}`,
|
|
1951
|
+
"Configuration Updated"
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
async function handleConfigureGlobalPath() {
|
|
1955
|
+
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
1956
|
+
const fs17 = await import("fs");
|
|
1957
|
+
const path16 = await import("path");
|
|
1958
|
+
note2(
|
|
1959
|
+
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
1960
|
+
and coordinate across projects.
|
|
1961
|
+
|
|
1962
|
+
Your current setup uses ${pc3.cyan("workspace")} mode, which stores data
|
|
1963
|
+
locally in each project. MCP needs a central location.`,
|
|
1964
|
+
"Global Path Required"
|
|
1965
|
+
);
|
|
1966
|
+
const resolvedPath = await resolveGlobalPath2();
|
|
1967
|
+
if (!resolvedPath) {
|
|
1968
|
+
return false;
|
|
1969
|
+
}
|
|
1970
|
+
try {
|
|
1971
|
+
if (!fs17.existsSync(resolvedPath)) {
|
|
1972
|
+
fs17.mkdirSync(resolvedPath, { recursive: true });
|
|
1973
|
+
}
|
|
1974
|
+
const config = loadMCPConfig();
|
|
1975
|
+
saveMCPConfig(config);
|
|
1976
|
+
note2(
|
|
1977
|
+
`${pc3.green("\u2713")} Global path configured: ${pc3.cyan(resolvedPath)}
|
|
1978
|
+
|
|
1979
|
+
MCP config will be stored at:
|
|
1980
|
+
${path16.join(resolvedPath, "mcp.yaml")}`,
|
|
1981
|
+
"Configuration Saved"
|
|
1982
|
+
);
|
|
1983
|
+
return true;
|
|
1984
|
+
} catch (error) {
|
|
1985
|
+
note2(
|
|
1986
|
+
`${pc3.red("\u2717")} Failed to create directory: ${error instanceof Error ? error.message : String(error)}`,
|
|
1987
|
+
"Error"
|
|
1988
|
+
);
|
|
1989
|
+
return false;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
var init_configure = __esm({
|
|
1993
|
+
"src/mcp/commands/configure.ts"() {
|
|
1994
|
+
"use strict";
|
|
1995
|
+
init_config();
|
|
1996
|
+
init_detection();
|
|
1997
|
+
init_logger();
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
|
|
2001
|
+
// src/mcp/commands/install-wizard.ts
|
|
2002
|
+
import { multiselect as multiselect2, note as note3, isCancel as isCancel3 } from "@clack/prompts";
|
|
2003
|
+
import pc4 from "picocolors";
|
|
2004
|
+
async function runInstallWizard(workspacePath) {
|
|
2005
|
+
const status = checkInstallStatus(workspacePath);
|
|
2006
|
+
const options = [
|
|
2007
|
+
{
|
|
2008
|
+
value: "antigravity",
|
|
2009
|
+
label: "Antigravity IDE",
|
|
2010
|
+
hint: status.antigravity ? pc4.green("\u2713 Installed") : pc4.dim("Not installed")
|
|
2011
|
+
},
|
|
2012
|
+
{
|
|
2013
|
+
value: "vscode-global",
|
|
2014
|
+
label: "VSCode (Global Settings)",
|
|
2015
|
+
hint: status.vscodeGlobal ? pc4.green("\u2713 Installed") : pc4.dim("Not installed")
|
|
2016
|
+
},
|
|
2017
|
+
{
|
|
2018
|
+
value: "vscode-workspace",
|
|
2019
|
+
label: "VSCode (Workspace Config)",
|
|
2020
|
+
hint: status.vscodeWorkspace ? pc4.green("\u2713 Installed") : pc4.dim("Not installed")
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
value: "claude",
|
|
2024
|
+
label: "Claude Desktop",
|
|
2025
|
+
hint: status.claude ? pc4.green("\u2713 Installed") : pc4.dim("Not installed")
|
|
2026
|
+
}
|
|
2027
|
+
];
|
|
2028
|
+
const selected = await multiselect2({
|
|
2029
|
+
message: "Select where to install RRCE MCP Server:",
|
|
2030
|
+
options,
|
|
2031
|
+
initialValues: [
|
|
2032
|
+
...status.antigravity ? ["antigravity"] : [],
|
|
2033
|
+
...status.vscodeGlobal ? ["vscode-global"] : [],
|
|
2034
|
+
...status.vscodeWorkspace ? ["vscode-workspace"] : [],
|
|
2035
|
+
...status.claude ? ["claude"] : []
|
|
2036
|
+
],
|
|
2037
|
+
required: false
|
|
2038
|
+
});
|
|
2039
|
+
if (isCancel3(selected)) return;
|
|
2040
|
+
const targets = selected;
|
|
2041
|
+
const results = [];
|
|
2042
|
+
for (const target of targets) {
|
|
2043
|
+
const success = installToConfig(target, workspacePath);
|
|
2044
|
+
const label = getTargetLabel(target);
|
|
2045
|
+
results.push(`${label}: ${success ? pc4.green("\u2713 Success") : pc4.red("\u2717 Failed")}`);
|
|
2046
|
+
}
|
|
2047
|
+
if (results.length > 0) {
|
|
2048
|
+
note3(results.join("\n"), "Installation Results");
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
var init_install_wizard = __esm({
|
|
2052
|
+
"src/mcp/commands/install-wizard.ts"() {
|
|
2053
|
+
"use strict";
|
|
2054
|
+
init_install();
|
|
2055
|
+
}
|
|
2056
|
+
});
|
|
2057
|
+
|
|
2058
|
+
// src/mcp/ui/Header.tsx
|
|
2059
|
+
import "react";
|
|
2060
|
+
import { Box, Text } from "ink";
|
|
2061
|
+
import { jsx } from "react/jsx-runtime";
|
|
2062
|
+
var Header;
|
|
2063
|
+
var init_Header = __esm({
|
|
2064
|
+
"src/mcp/ui/Header.tsx"() {
|
|
2065
|
+
"use strict";
|
|
2066
|
+
Header = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingBottom: 1, children: /* @__PURE__ */ jsx(Box, { borderStyle: "double", borderColor: "cyan", paddingX: 2, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: " RRCE MCP Hub " }) }) });
|
|
2067
|
+
}
|
|
2068
|
+
});
|
|
2069
|
+
|
|
2070
|
+
// src/mcp/ui/StatusBoard.tsx
|
|
2071
|
+
import "react";
|
|
2072
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
2073
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
2074
|
+
var StatusBoard;
|
|
2075
|
+
var init_StatusBoard = __esm({
|
|
2076
|
+
"src/mcp/ui/StatusBoard.tsx"() {
|
|
2077
|
+
"use strict";
|
|
2078
|
+
StatusBoard = ({ exposedLabel, port, pid }) => {
|
|
2079
|
+
return /* @__PURE__ */ jsx2(Box2, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { children: [
|
|
1845
2080
|
"\u{1F4CB} ",
|
|
1846
2081
|
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: exposedLabel }),
|
|
1847
2082
|
" ",
|
|
@@ -2010,12 +2245,15 @@ var init_App = __esm({
|
|
|
2010
2245
|
if (input === "q" || key.ctrl && input === "c") {
|
|
2011
2246
|
stopMCPServer();
|
|
2012
2247
|
onExit();
|
|
2248
|
+
exit();
|
|
2013
2249
|
}
|
|
2014
2250
|
if (input === "p") {
|
|
2015
2251
|
onConfigure();
|
|
2252
|
+
exit();
|
|
2016
2253
|
}
|
|
2017
2254
|
if (input === "i") {
|
|
2018
2255
|
onInstall();
|
|
2256
|
+
exit();
|
|
2019
2257
|
}
|
|
2020
2258
|
if (input === "c") {
|
|
2021
2259
|
setLogs([]);
|
|
@@ -2040,13 +2278,206 @@ var init_App = __esm({
|
|
|
2040
2278
|
}
|
|
2041
2279
|
});
|
|
2042
2280
|
|
|
2281
|
+
// src/mcp/commands/start.ts
|
|
2282
|
+
import { confirm, isCancel as isCancel4, text } from "@clack/prompts";
|
|
2283
|
+
async function handleStartServer() {
|
|
2284
|
+
const React7 = await import("react");
|
|
2285
|
+
const { render } = await import("ink");
|
|
2286
|
+
const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
|
|
2287
|
+
const config = loadMCPConfig();
|
|
2288
|
+
const projects = scanForProjects();
|
|
2289
|
+
const exposedProjects = projects.filter((p) => {
|
|
2290
|
+
const cfg = config.projects.find(
|
|
2291
|
+
(c) => c.path && c.path === p.dataPath || !c.path && c.name === p.name
|
|
2292
|
+
);
|
|
2293
|
+
return cfg?.expose ?? config.defaults.includeNew;
|
|
2294
|
+
});
|
|
2295
|
+
if (exposedProjects.length === 0) {
|
|
2296
|
+
const shouldConfig = await confirm({
|
|
2297
|
+
message: "No projects are currently exposed. Configure now?",
|
|
2298
|
+
initialValue: true
|
|
2299
|
+
});
|
|
2300
|
+
if (shouldConfig && !isCancel4(shouldConfig)) {
|
|
2301
|
+
await handleConfigure();
|
|
2302
|
+
return handleStartServer();
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
const status = getMCPServerStatus();
|
|
2306
|
+
let initialPort = config.server.port;
|
|
2307
|
+
if (!status.running) {
|
|
2308
|
+
const portInput = await text({
|
|
2309
|
+
message: "Select port for MCP Server",
|
|
2310
|
+
initialValue: config.server.port.toString(),
|
|
2311
|
+
placeholder: "3200",
|
|
2312
|
+
validate(value) {
|
|
2313
|
+
if (isNaN(Number(value))) return "Port must be a number";
|
|
2314
|
+
}
|
|
2315
|
+
});
|
|
2316
|
+
if (isCancel4(portInput)) return;
|
|
2317
|
+
const newPort = parseInt(portInput, 10);
|
|
2318
|
+
if (newPort !== config.server.port) {
|
|
2319
|
+
config.server.port = newPort;
|
|
2320
|
+
saveMCPConfig(config);
|
|
2321
|
+
initialPort = newPort;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
console.clear();
|
|
2325
|
+
let keepRunning = true;
|
|
2326
|
+
while (keepRunning) {
|
|
2327
|
+
let nextAction = "exit";
|
|
2328
|
+
process.stdin.resume();
|
|
2329
|
+
const app = render(React7.createElement(App2, {
|
|
2330
|
+
initialPort,
|
|
2331
|
+
onExit: () => {
|
|
2332
|
+
nextAction = "exit";
|
|
2333
|
+
},
|
|
2334
|
+
onConfigure: () => {
|
|
2335
|
+
nextAction = "configure";
|
|
2336
|
+
},
|
|
2337
|
+
onInstall: () => {
|
|
2338
|
+
nextAction = "install";
|
|
2339
|
+
}
|
|
2340
|
+
}), {
|
|
2341
|
+
exitOnCtrlC: false
|
|
2342
|
+
// We handle this in App
|
|
2343
|
+
});
|
|
2344
|
+
await app.waitUntilExit();
|
|
2345
|
+
if (nextAction === "exit") {
|
|
2346
|
+
keepRunning = false;
|
|
2347
|
+
} else if (nextAction === "configure") {
|
|
2348
|
+
console.clear();
|
|
2349
|
+
await handleConfigure();
|
|
2350
|
+
} else if (nextAction === "install") {
|
|
2351
|
+
console.clear();
|
|
2352
|
+
const workspacePath = detectWorkspaceRoot();
|
|
2353
|
+
await runInstallWizard(workspacePath);
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
var init_start = __esm({
|
|
2358
|
+
"src/mcp/commands/start.ts"() {
|
|
2359
|
+
"use strict";
|
|
2360
|
+
init_config();
|
|
2361
|
+
init_detection();
|
|
2362
|
+
init_server();
|
|
2363
|
+
init_paths();
|
|
2364
|
+
init_configure();
|
|
2365
|
+
init_install_wizard();
|
|
2366
|
+
}
|
|
2367
|
+
});
|
|
2368
|
+
|
|
2369
|
+
// src/mcp/commands/status.ts
|
|
2370
|
+
import { spinner as spinner2, note as note4 } from "@clack/prompts";
|
|
2371
|
+
import pc5 from "picocolors";
|
|
2372
|
+
async function handleShowStatus() {
|
|
2373
|
+
const s = spinner2();
|
|
2374
|
+
s.start("Loading projects...");
|
|
2375
|
+
const config = loadMCPConfig();
|
|
2376
|
+
const projects = scanForProjects();
|
|
2377
|
+
const workspacePath = detectWorkspaceRoot();
|
|
2378
|
+
const installStatus = checkInstallStatus(workspacePath);
|
|
2379
|
+
s.stop("Projects loaded");
|
|
2380
|
+
if (projects.length === 0) {
|
|
2381
|
+
note4('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
const lines = [
|
|
2385
|
+
`${pc5.bold("Installation Status")}`,
|
|
2386
|
+
"",
|
|
2387
|
+
` Antigravity: ${installStatus.antigravity ? pc5.green("\u2713 Installed") : pc5.dim("Not installed")}`,
|
|
2388
|
+
` VSCode (Global): ${installStatus.vscodeGlobal ? pc5.green("\u2713 Installed") : pc5.dim("Not installed")}`,
|
|
2389
|
+
` VSCode (Workspace): ${installStatus.vscodeWorkspace ? pc5.green("\u2713 Installed") : pc5.dim("Not installed")}`,
|
|
2390
|
+
` Claude Desktop: ${installStatus.claude ? pc5.green("\u2713 Installed") : pc5.dim("Not installed")}`,
|
|
2391
|
+
"",
|
|
2392
|
+
`${pc5.bold("Project Status")}`,
|
|
2393
|
+
""
|
|
2394
|
+
];
|
|
2395
|
+
for (const project of projects) {
|
|
2396
|
+
const projectConfig = config.projects.find((p) => p.name === project.name);
|
|
2397
|
+
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
2398
|
+
const status = isExposed ? pc5.green("\u2713 exposed") : pc5.dim("\u25CB hidden");
|
|
2399
|
+
const source = pc5.dim(`(${project.source})`);
|
|
2400
|
+
lines.push(` ${status} ${project.name} ${source}`);
|
|
2401
|
+
}
|
|
2402
|
+
lines.push("");
|
|
2403
|
+
lines.push(pc5.dim(`Config: ${getMCPConfigPath()}`));
|
|
2404
|
+
const serverStatus = getMCPServerStatus();
|
|
2405
|
+
if (serverStatus.running) {
|
|
2406
|
+
lines.push(pc5.green(`Server: running on port ${serverStatus.port}`));
|
|
2407
|
+
} else {
|
|
2408
|
+
lines.push(pc5.dim("Server: not running"));
|
|
2409
|
+
}
|
|
2410
|
+
note4(lines.join("\n"), "MCP Hub Status");
|
|
2411
|
+
}
|
|
2412
|
+
var init_status = __esm({
|
|
2413
|
+
"src/mcp/commands/status.ts"() {
|
|
2414
|
+
"use strict";
|
|
2415
|
+
init_config();
|
|
2416
|
+
init_detection();
|
|
2417
|
+
init_paths();
|
|
2418
|
+
init_server();
|
|
2419
|
+
init_install();
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2422
|
+
|
|
2423
|
+
// src/mcp/commands/help.ts
|
|
2424
|
+
import { note as note5 } from "@clack/prompts";
|
|
2425
|
+
import pc6 from "picocolors";
|
|
2426
|
+
function showHelp() {
|
|
2427
|
+
const help = `
|
|
2428
|
+
${pc6.bold("RRCE MCP Hub")} - Cross-project AI assistant server
|
|
2429
|
+
|
|
2430
|
+
${pc6.bold("ABOUT")}
|
|
2431
|
+
MCP (Model Context Protocol) allows AI assistants like Claude to
|
|
2432
|
+
access your project knowledge in real-time. The RRCE MCP Hub
|
|
2433
|
+
provides a central server that exposes selected projects.
|
|
2434
|
+
|
|
2435
|
+
${pc6.bold("MENU OPTIONS")}
|
|
2436
|
+
${pc6.cyan("Start MCP server")} Start the server for AI access
|
|
2437
|
+
${pc6.cyan("Configure projects")} Choose which projects to expose
|
|
2438
|
+
${pc6.cyan("Install to IDE")} Add to Antigravity, VSCode, or Claude
|
|
2439
|
+
${pc6.cyan("View status")} See which projects are exposed
|
|
2440
|
+
|
|
2441
|
+
${pc6.bold("DIRECT COMMANDS")}
|
|
2442
|
+
${pc6.dim("rrce-workflow mcp start")} Start server directly
|
|
2443
|
+
${pc6.dim("rrce-workflow mcp stop")} Stop server directly
|
|
2444
|
+
${pc6.dim("rrce-workflow mcp status")} Show status directly
|
|
2445
|
+
${pc6.dim("rrce-workflow mcp help")} Show this help
|
|
2446
|
+
|
|
2447
|
+
${pc6.bold("IDE INSTALLATION")}
|
|
2448
|
+
${pc6.cyan("Antigravity")} ~/.gemini/antigravity/mcp_config.json
|
|
2449
|
+
${pc6.cyan("VSCode Global")} ~/.config/Code/User/settings.json
|
|
2450
|
+
${pc6.cyan("VSCode Workspace")} .vscode/mcp.json
|
|
2451
|
+
${pc6.cyan("Claude Desktop")} ~/.config/claude/claude_desktop_config.json
|
|
2452
|
+
|
|
2453
|
+
${pc6.bold("SERVER COMMANDS")} (while running)
|
|
2454
|
+
${pc6.cyan("q")} Stop and quit ${pc6.cyan("p")} Reconfigure projects
|
|
2455
|
+
${pc6.cyan("i")} Install to IDE ${pc6.cyan("r")} Reload config
|
|
2456
|
+
${pc6.cyan("c")} Clear logs ${pc6.cyan("?")} Show help
|
|
2457
|
+
|
|
2458
|
+
${pc6.bold("RESOURCES EXPOSED")}
|
|
2459
|
+
${pc6.cyan("rrce://projects")} List all exposed projects
|
|
2460
|
+
${pc6.cyan("rrce://projects/{name}/context")} Get project context
|
|
2461
|
+
${pc6.cyan("rrce://projects/{name}/tasks")} Get project tasks
|
|
2462
|
+
`;
|
|
2463
|
+
note5(help.trim(), "Help");
|
|
2464
|
+
}
|
|
2465
|
+
var init_help = __esm({
|
|
2466
|
+
"src/mcp/commands/help.ts"() {
|
|
2467
|
+
"use strict";
|
|
2468
|
+
}
|
|
2469
|
+
});
|
|
2470
|
+
|
|
2043
2471
|
// src/mcp/index.ts
|
|
2044
2472
|
var mcp_exports = {};
|
|
2045
2473
|
__export(mcp_exports, {
|
|
2474
|
+
handleConfigure: () => handleConfigure,
|
|
2475
|
+
handleConfigureGlobalPath: () => handleConfigureGlobalPath,
|
|
2476
|
+
handleStartServer: () => handleStartServer,
|
|
2046
2477
|
runMCP: () => runMCP
|
|
2047
2478
|
});
|
|
2048
|
-
import { intro, outro, select as select2,
|
|
2049
|
-
import
|
|
2479
|
+
import { intro, outro, select as select2, confirm as confirm2, note as note6, cancel, isCancel as isCancel5 } from "@clack/prompts";
|
|
2480
|
+
import pc7 from "picocolors";
|
|
2050
2481
|
async function runMCP(subcommand2) {
|
|
2051
2482
|
if (subcommand2) {
|
|
2052
2483
|
switch (subcommand2) {
|
|
@@ -2068,59 +2499,62 @@ async function runMCP(subcommand2) {
|
|
|
2068
2499
|
case "help":
|
|
2069
2500
|
showHelp();
|
|
2070
2501
|
return;
|
|
2502
|
+
case "configure":
|
|
2503
|
+
await handleConfigure();
|
|
2504
|
+
return;
|
|
2071
2505
|
}
|
|
2072
2506
|
}
|
|
2073
|
-
intro(
|
|
2507
|
+
intro(pc7.bgCyan(pc7.black(" RRCE MCP Hub ")));
|
|
2074
2508
|
const workspacePath = detectWorkspaceRoot();
|
|
2075
2509
|
const globalPathCheck = await ensureMCPGlobalPath();
|
|
2076
2510
|
if (!globalPathCheck.configured) {
|
|
2077
2511
|
const configured = await handleConfigureGlobalPath();
|
|
2078
2512
|
if (!configured) {
|
|
2079
|
-
outro(
|
|
2513
|
+
outro(pc7.yellow("MCP requires a global storage path. Setup cancelled."));
|
|
2080
2514
|
return;
|
|
2081
2515
|
}
|
|
2082
2516
|
}
|
|
2083
2517
|
const installed = isInstalledAnywhere(workspacePath);
|
|
2084
2518
|
if (!installed) {
|
|
2085
|
-
|
|
2086
|
-
`${
|
|
2519
|
+
note6(
|
|
2520
|
+
`${pc7.bold("Welcome to RRCE MCP Hub!")}
|
|
2087
2521
|
|
|
2088
2522
|
MCP (Model Context Protocol) allows AI assistants to access your
|
|
2089
2523
|
project knowledge in real-time. Let's get you set up.`,
|
|
2090
2524
|
"Getting Started"
|
|
2091
2525
|
);
|
|
2092
|
-
const shouldInstall = await
|
|
2526
|
+
const shouldInstall = await confirm2({
|
|
2093
2527
|
message: "Install MCP server to your IDE(s)?",
|
|
2094
2528
|
initialValue: true
|
|
2095
2529
|
});
|
|
2096
|
-
if (shouldInstall && !
|
|
2097
|
-
await
|
|
2530
|
+
if (shouldInstall && !isCancel5(shouldInstall)) {
|
|
2531
|
+
await runInstallWizard(workspacePath);
|
|
2098
2532
|
const config2 = loadMCPConfig();
|
|
2099
2533
|
const exposedCount2 = config2.projects.filter((p) => p.expose).length;
|
|
2100
2534
|
if (exposedCount2 === 0) {
|
|
2101
2535
|
await handleConfigure();
|
|
2102
2536
|
}
|
|
2103
|
-
const shouldStart = await
|
|
2537
|
+
const shouldStart = await confirm2({
|
|
2104
2538
|
message: "Start the MCP server now?",
|
|
2105
2539
|
initialValue: true
|
|
2106
2540
|
});
|
|
2107
|
-
if (shouldStart && !
|
|
2541
|
+
if (shouldStart && !isCancel5(shouldStart)) {
|
|
2108
2542
|
await handleStartServer();
|
|
2109
2543
|
}
|
|
2110
2544
|
}
|
|
2111
|
-
outro(
|
|
2545
|
+
outro(pc7.green("MCP Hub setup complete!"));
|
|
2112
2546
|
return;
|
|
2113
2547
|
}
|
|
2114
2548
|
const config = loadMCPConfig();
|
|
2115
2549
|
const exposedCount = config.projects.filter((p) => p.expose).length;
|
|
2116
2550
|
if (exposedCount === 0 && !config.defaults.includeNew) {
|
|
2117
|
-
|
|
2551
|
+
note6("MCP is installed but no projects are exposed. Let's configure that.", "Configuration Needed");
|
|
2118
2552
|
await handleConfigure();
|
|
2119
2553
|
}
|
|
2120
2554
|
let running = true;
|
|
2121
2555
|
while (running) {
|
|
2122
2556
|
const serverStatus = getMCPServerStatus();
|
|
2123
|
-
const serverLabel = serverStatus.running ?
|
|
2557
|
+
const serverLabel = serverStatus.running ? pc7.green("\u25CF Running") : pc7.dim("\u25CB Stopped");
|
|
2124
2558
|
const currentStatus = checkInstallStatus(workspacePath);
|
|
2125
2559
|
const installedCount = [currentStatus.antigravity, currentStatus.claude, currentStatus.vscodeGlobal, currentStatus.vscodeWorkspace].filter(Boolean).length;
|
|
2126
2560
|
const action = await select2({
|
|
@@ -2134,7 +2568,7 @@ project knowledge in real-time. Let's get you set up.`,
|
|
|
2134
2568
|
{ value: "exit", label: "\u21A9 Exit", hint: "Return to shell" }
|
|
2135
2569
|
]
|
|
2136
2570
|
});
|
|
2137
|
-
if (
|
|
2571
|
+
if (isCancel5(action)) {
|
|
2138
2572
|
cancel("MCP Hub closed.");
|
|
2139
2573
|
return;
|
|
2140
2574
|
}
|
|
@@ -2146,7 +2580,7 @@ project knowledge in real-time. Let's get you set up.`,
|
|
|
2146
2580
|
await handleConfigure();
|
|
2147
2581
|
break;
|
|
2148
2582
|
case "install":
|
|
2149
|
-
await
|
|
2583
|
+
await runInstallWizard(workspacePath);
|
|
2150
2584
|
break;
|
|
2151
2585
|
case "status":
|
|
2152
2586
|
await handleShowStatus();
|
|
@@ -2159,330 +2593,47 @@ project knowledge in real-time. Let's get you set up.`,
|
|
|
2159
2593
|
break;
|
|
2160
2594
|
}
|
|
2161
2595
|
}
|
|
2162
|
-
outro(
|
|
2163
|
-
}
|
|
2164
|
-
async function handleInstallWizard(workspacePath) {
|
|
2165
|
-
const status = checkInstallStatus(workspacePath);
|
|
2166
|
-
const options = [
|
|
2167
|
-
{
|
|
2168
|
-
value: "antigravity",
|
|
2169
|
-
label: "Antigravity IDE",
|
|
2170
|
-
hint: status.antigravity ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
2171
|
-
},
|
|
2172
|
-
{
|
|
2173
|
-
value: "vscode-global",
|
|
2174
|
-
label: "VSCode (Global Settings)",
|
|
2175
|
-
hint: status.vscodeGlobal ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
2176
|
-
},
|
|
2177
|
-
{
|
|
2178
|
-
value: "vscode-workspace",
|
|
2179
|
-
label: "VSCode (Workspace Config)",
|
|
2180
|
-
hint: status.vscodeWorkspace ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
2181
|
-
},
|
|
2182
|
-
{
|
|
2183
|
-
value: "claude",
|
|
2184
|
-
label: "Claude Desktop",
|
|
2185
|
-
hint: status.claude ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
2186
|
-
}
|
|
2187
|
-
];
|
|
2188
|
-
const selected = await multiselect({
|
|
2189
|
-
message: "Select where to install RRCE MCP Server:",
|
|
2190
|
-
options,
|
|
2191
|
-
initialValues: [
|
|
2192
|
-
...status.antigravity ? ["antigravity"] : [],
|
|
2193
|
-
...status.vscodeGlobal ? ["vscode-global"] : [],
|
|
2194
|
-
...status.vscodeWorkspace ? ["vscode-workspace"] : [],
|
|
2195
|
-
...status.claude ? ["claude"] : []
|
|
2196
|
-
],
|
|
2197
|
-
required: false
|
|
2198
|
-
});
|
|
2199
|
-
if (isCancel2(selected)) return;
|
|
2200
|
-
const targets = selected;
|
|
2201
|
-
const results = [];
|
|
2202
|
-
for (const target of targets) {
|
|
2203
|
-
const success = installToConfig(target, workspacePath);
|
|
2204
|
-
const label = getTargetLabel(target);
|
|
2205
|
-
results.push(`${label}: ${success ? pc3.green("\u2713 Success") : pc3.red("\u2717 Failed")}`);
|
|
2206
|
-
}
|
|
2207
|
-
if (results.length > 0) {
|
|
2208
|
-
note2(results.join("\n"), "Installation Results");
|
|
2209
|
-
}
|
|
2210
|
-
}
|
|
2211
|
-
async function handleStartServer() {
|
|
2212
|
-
const React7 = await import("react");
|
|
2213
|
-
const { render } = await import("ink");
|
|
2214
|
-
const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
|
|
2215
|
-
const { loadMCPConfig: loadMCPConfig2, saveMCPConfig: saveMCPConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2216
|
-
const config = loadMCPConfig2();
|
|
2217
|
-
const projects = scanForProjects();
|
|
2218
|
-
const exposedProjects = projects.filter((p) => {
|
|
2219
|
-
const cfg = config.projects.find((c) => c.name === p.name);
|
|
2220
|
-
return cfg?.expose ?? config.defaults.includeNew;
|
|
2221
|
-
});
|
|
2222
|
-
if (exposedProjects.length === 0) {
|
|
2223
|
-
const shouldConfig = await confirm({
|
|
2224
|
-
message: "No projects are currently exposed. Configure now?",
|
|
2225
|
-
initialValue: true
|
|
2226
|
-
});
|
|
2227
|
-
if (shouldConfig && !isCancel2(shouldConfig)) {
|
|
2228
|
-
await handleConfigure();
|
|
2229
|
-
return handleStartServer();
|
|
2230
|
-
}
|
|
2231
|
-
}
|
|
2232
|
-
const status = getMCPServerStatus();
|
|
2233
|
-
let initialPort = config.server.port;
|
|
2234
|
-
if (!status.running) {
|
|
2235
|
-
const portInput = await text({
|
|
2236
|
-
message: "Select port for MCP Server",
|
|
2237
|
-
initialValue: config.server.port.toString(),
|
|
2238
|
-
placeholder: "3200",
|
|
2239
|
-
validate(value) {
|
|
2240
|
-
if (isNaN(Number(value))) return "Port must be a number";
|
|
2241
|
-
}
|
|
2242
|
-
});
|
|
2243
|
-
if (isCancel2(portInput)) return;
|
|
2244
|
-
const newPort = parseInt(portInput, 10);
|
|
2245
|
-
if (newPort !== config.server.port) {
|
|
2246
|
-
config.server.port = newPort;
|
|
2247
|
-
saveMCPConfig2(config);
|
|
2248
|
-
initialPort = newPort;
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
console.clear();
|
|
2252
|
-
let keepRunning = true;
|
|
2253
|
-
while (keepRunning) {
|
|
2254
|
-
let nextAction = "exit";
|
|
2255
|
-
process.stdin.resume();
|
|
2256
|
-
const app = render(React7.createElement(App2, {
|
|
2257
|
-
initialPort,
|
|
2258
|
-
onExit: () => {
|
|
2259
|
-
nextAction = "exit";
|
|
2260
|
-
},
|
|
2261
|
-
onConfigure: () => {
|
|
2262
|
-
nextAction = "configure";
|
|
2263
|
-
},
|
|
2264
|
-
onInstall: () => {
|
|
2265
|
-
nextAction = "install";
|
|
2266
|
-
}
|
|
2267
|
-
}), {
|
|
2268
|
-
exitOnCtrlC: false
|
|
2269
|
-
// We handle this in App
|
|
2270
|
-
});
|
|
2271
|
-
await app.waitUntilExit();
|
|
2272
|
-
if (nextAction === "exit") {
|
|
2273
|
-
keepRunning = false;
|
|
2274
|
-
} else if (nextAction === "configure") {
|
|
2275
|
-
console.clear();
|
|
2276
|
-
await handleConfigure();
|
|
2277
|
-
} else if (nextAction === "install") {
|
|
2278
|
-
console.clear();
|
|
2279
|
-
const workspacePath = detectWorkspaceRoot();
|
|
2280
|
-
await handleInstallWizard(workspacePath);
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
async function handleConfigureGlobalPath() {
|
|
2285
|
-
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
2286
|
-
const fs17 = await import("fs");
|
|
2287
|
-
const path16 = await import("path");
|
|
2288
|
-
note2(
|
|
2289
|
-
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
2290
|
-
and coordinate across projects.
|
|
2291
|
-
|
|
2292
|
-
Your current setup uses ${pc3.cyan("workspace")} mode, which stores data
|
|
2293
|
-
locally in each project. MCP needs a central location.`,
|
|
2294
|
-
"Global Path Required"
|
|
2295
|
-
);
|
|
2296
|
-
const resolvedPath = await resolveGlobalPath2();
|
|
2297
|
-
if (!resolvedPath) {
|
|
2298
|
-
return false;
|
|
2299
|
-
}
|
|
2300
|
-
try {
|
|
2301
|
-
if (!fs17.existsSync(resolvedPath)) {
|
|
2302
|
-
fs17.mkdirSync(resolvedPath, { recursive: true });
|
|
2303
|
-
}
|
|
2304
|
-
const config = loadMCPConfig();
|
|
2305
|
-
saveMCPConfig(config);
|
|
2306
|
-
note2(
|
|
2307
|
-
`${pc3.green("\u2713")} Global path configured: ${pc3.cyan(resolvedPath)}
|
|
2308
|
-
|
|
2309
|
-
MCP config will be stored at:
|
|
2310
|
-
${path16.join(resolvedPath, "mcp.yaml")}`,
|
|
2311
|
-
"Configuration Saved"
|
|
2312
|
-
);
|
|
2313
|
-
return true;
|
|
2314
|
-
} catch (error) {
|
|
2315
|
-
note2(
|
|
2316
|
-
`${pc3.red("\u2717")} Failed to create directory: ${error instanceof Error ? error.message : String(error)}`,
|
|
2317
|
-
"Error"
|
|
2318
|
-
);
|
|
2319
|
-
return false;
|
|
2320
|
-
}
|
|
2321
|
-
}
|
|
2322
|
-
async function handleShowStatus() {
|
|
2323
|
-
const s = spinner();
|
|
2324
|
-
s.start("Loading projects...");
|
|
2325
|
-
const config = loadMCPConfig();
|
|
2326
|
-
const projects = scanForProjects();
|
|
2327
|
-
const workspacePath = detectWorkspaceRoot();
|
|
2328
|
-
const installStatus = checkInstallStatus(workspacePath);
|
|
2329
|
-
s.stop("Projects loaded");
|
|
2330
|
-
if (projects.length === 0) {
|
|
2331
|
-
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
2332
|
-
return;
|
|
2333
|
-
}
|
|
2334
|
-
const lines = [
|
|
2335
|
-
`${pc3.bold("Installation Status")}`,
|
|
2336
|
-
"",
|
|
2337
|
-
` Antigravity: ${installStatus.antigravity ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2338
|
-
` VSCode (Global): ${installStatus.vscodeGlobal ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2339
|
-
` VSCode (Workspace): ${installStatus.vscodeWorkspace ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2340
|
-
` Claude Desktop: ${installStatus.claude ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2341
|
-
"",
|
|
2342
|
-
`${pc3.bold("Project Status")}`,
|
|
2343
|
-
""
|
|
2344
|
-
];
|
|
2345
|
-
for (const project of projects) {
|
|
2346
|
-
const projectConfig = config.projects.find((p) => p.name === project.name);
|
|
2347
|
-
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
2348
|
-
const status = isExposed ? pc3.green("\u2713 exposed") : pc3.dim("\u25CB hidden");
|
|
2349
|
-
const source = pc3.dim(`(${project.source})`);
|
|
2350
|
-
lines.push(` ${status} ${project.name} ${source}`);
|
|
2351
|
-
}
|
|
2352
|
-
lines.push("");
|
|
2353
|
-
lines.push(pc3.dim(`Config: ${getMCPConfigPath()}`));
|
|
2354
|
-
const serverStatus = getMCPServerStatus();
|
|
2355
|
-
if (serverStatus.running) {
|
|
2356
|
-
lines.push(pc3.green(`Server: running on port ${serverStatus.port}`));
|
|
2357
|
-
} else {
|
|
2358
|
-
lines.push(pc3.dim("Server: not running"));
|
|
2359
|
-
}
|
|
2360
|
-
note2(lines.join("\n"), "MCP Hub Status");
|
|
2361
|
-
}
|
|
2362
|
-
async function handleConfigure() {
|
|
2363
|
-
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
2364
|
-
const s = spinner();
|
|
2365
|
-
s.start("Scanning for projects...");
|
|
2366
|
-
const config = loadMCPConfig();
|
|
2367
|
-
const projects = scanForProjects();
|
|
2368
|
-
logger2.info("Configure: Loaded config", { projects: config.projects, defaultMode: config.defaults.includeNew });
|
|
2369
|
-
s.stop("Projects found");
|
|
2370
|
-
if (projects.length === 0) {
|
|
2371
|
-
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
2372
|
-
return;
|
|
2373
|
-
}
|
|
2374
|
-
const options = projects.map((project) => {
|
|
2375
|
-
const projectConfig = config.projects.find((p) => p.name === project.name);
|
|
2376
|
-
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
2377
|
-
return {
|
|
2378
|
-
value: project.name,
|
|
2379
|
-
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
2380
|
-
hint: project.dataPath
|
|
2381
|
-
};
|
|
2382
|
-
});
|
|
2383
|
-
const currentlyExposed = projects.filter((p) => {
|
|
2384
|
-
const cfg = config.projects.find((c) => c.name === p.name);
|
|
2385
|
-
return cfg?.expose ?? config.defaults.includeNew;
|
|
2386
|
-
}).map((p) => p.name);
|
|
2387
|
-
const selected = await multiselect({
|
|
2388
|
-
message: "Select projects to expose via MCP:",
|
|
2389
|
-
options,
|
|
2390
|
-
initialValues: currentlyExposed,
|
|
2391
|
-
required: false
|
|
2392
|
-
});
|
|
2393
|
-
if (isCancel2(selected)) {
|
|
2394
|
-
return;
|
|
2395
|
-
}
|
|
2396
|
-
const selectedNames = selected;
|
|
2397
|
-
logger2.info("Configure: User selected projects", selectedNames);
|
|
2398
|
-
for (const project of projects) {
|
|
2399
|
-
const shouldExpose = selectedNames.includes(project.name);
|
|
2400
|
-
setProjectConfig(config, project.name, shouldExpose);
|
|
2401
|
-
}
|
|
2402
|
-
saveMCPConfig(config);
|
|
2403
|
-
logger2.info("Configure: Config saved", config);
|
|
2404
|
-
const exposedCount = selectedNames.length;
|
|
2405
|
-
note2(
|
|
2406
|
-
`${pc3.green("\u2713")} Configuration saved!
|
|
2407
|
-
|
|
2408
|
-
Exposed projects: ${exposedCount}
|
|
2409
|
-
Hidden projects: ${projects.length - exposedCount}`,
|
|
2410
|
-
"Configuration Updated"
|
|
2411
|
-
);
|
|
2596
|
+
outro(pc7.green("MCP Hub closed."));
|
|
2412
2597
|
}
|
|
2413
2598
|
async function handleStopServer() {
|
|
2599
|
+
const { stopMCPServer: stopMCPServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
2414
2600
|
const status = getMCPServerStatus();
|
|
2415
2601
|
if (!status.running) {
|
|
2416
|
-
|
|
2602
|
+
note6("MCP server is not running.", "Status");
|
|
2417
2603
|
return;
|
|
2418
2604
|
}
|
|
2419
|
-
const confirmed = await
|
|
2605
|
+
const confirmed = await confirm2({
|
|
2420
2606
|
message: "Stop the MCP server?",
|
|
2421
2607
|
initialValue: true
|
|
2422
2608
|
});
|
|
2423
|
-
if (
|
|
2609
|
+
if (isCancel5(confirmed) || !confirmed) {
|
|
2424
2610
|
return;
|
|
2425
2611
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
}
|
|
2429
|
-
function showHelp() {
|
|
2430
|
-
const help = `
|
|
2431
|
-
${pc3.bold("RRCE MCP Hub")} - Cross-project AI assistant server
|
|
2432
|
-
|
|
2433
|
-
${pc3.bold("ABOUT")}
|
|
2434
|
-
MCP (Model Context Protocol) allows AI assistants like Claude to
|
|
2435
|
-
access your project knowledge in real-time. The RRCE MCP Hub
|
|
2436
|
-
provides a central server that exposes selected projects.
|
|
2437
|
-
|
|
2438
|
-
${pc3.bold("MENU OPTIONS")}
|
|
2439
|
-
${pc3.cyan("Start MCP server")} Start the server for AI access
|
|
2440
|
-
${pc3.cyan("Configure projects")} Choose which projects to expose
|
|
2441
|
-
${pc3.cyan("Install to IDE")} Add to Antigravity, VSCode, or Claude
|
|
2442
|
-
${pc3.cyan("View status")} See which projects are exposed
|
|
2443
|
-
|
|
2444
|
-
${pc3.bold("DIRECT COMMANDS")}
|
|
2445
|
-
${pc3.dim("rrce-workflow mcp start")} Start server directly
|
|
2446
|
-
${pc3.dim("rrce-workflow mcp stop")} Stop server directly
|
|
2447
|
-
${pc3.dim("rrce-workflow mcp status")} Show status directly
|
|
2448
|
-
${pc3.dim("rrce-workflow mcp help")} Show this help
|
|
2449
|
-
|
|
2450
|
-
${pc3.bold("IDE INSTALLATION")}
|
|
2451
|
-
${pc3.cyan("Antigravity")} ~/.gemini/antigravity/mcp_config.json
|
|
2452
|
-
${pc3.cyan("VSCode Global")} ~/.config/Code/User/settings.json
|
|
2453
|
-
${pc3.cyan("VSCode Workspace")} .vscode/mcp.json
|
|
2454
|
-
${pc3.cyan("Claude Desktop")} ~/.config/claude/claude_desktop_config.json
|
|
2455
|
-
|
|
2456
|
-
${pc3.bold("SERVER COMMANDS")} (while running)
|
|
2457
|
-
${pc3.cyan("q")} Stop and quit ${pc3.cyan("p")} Reconfigure projects
|
|
2458
|
-
${pc3.cyan("i")} Install to IDE ${pc3.cyan("r")} Reload config
|
|
2459
|
-
${pc3.cyan("c")} Clear logs ${pc3.cyan("?")} Show help
|
|
2460
|
-
|
|
2461
|
-
${pc3.bold("RESOURCES EXPOSED")}
|
|
2462
|
-
${pc3.cyan("rrce://projects")} List all exposed projects
|
|
2463
|
-
${pc3.cyan("rrce://projects/{name}/context")} Get project context
|
|
2464
|
-
${pc3.cyan("rrce://projects/{name}/tasks")} Get project tasks
|
|
2465
|
-
`;
|
|
2466
|
-
note2(help.trim(), "Help");
|
|
2612
|
+
stopMCPServer2();
|
|
2613
|
+
note6(pc7.green("MCP server stopped."), "Server Stopped");
|
|
2467
2614
|
}
|
|
2468
2615
|
var init_mcp = __esm({
|
|
2469
2616
|
"src/mcp/index.ts"() {
|
|
2470
2617
|
"use strict";
|
|
2471
2618
|
init_config();
|
|
2472
|
-
init_detection();
|
|
2473
2619
|
init_server();
|
|
2474
2620
|
init_install();
|
|
2475
2621
|
init_paths();
|
|
2622
|
+
init_start();
|
|
2623
|
+
init_configure();
|
|
2624
|
+
init_status();
|
|
2625
|
+
init_install_wizard();
|
|
2626
|
+
init_help();
|
|
2476
2627
|
}
|
|
2477
2628
|
});
|
|
2478
2629
|
|
|
2479
2630
|
// src/commands/wizard/setup-flow.ts
|
|
2480
|
-
import { group, select as select3, multiselect as
|
|
2481
|
-
import
|
|
2631
|
+
import { group, select as select3, multiselect as multiselect3, confirm as confirm3, spinner as spinner3, note as note7, outro as outro2, cancel as cancel2, isCancel as isCancel6 } from "@clack/prompts";
|
|
2632
|
+
import pc8 from "picocolors";
|
|
2482
2633
|
import * as fs12 from "fs";
|
|
2483
2634
|
import * as path12 from "path";
|
|
2484
2635
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
2485
|
-
const s =
|
|
2636
|
+
const s = spinner3();
|
|
2486
2637
|
const config = await group(
|
|
2487
2638
|
{
|
|
2488
2639
|
storageMode: () => select3({
|
|
@@ -2493,7 +2644,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2493
2644
|
],
|
|
2494
2645
|
initialValue: "global"
|
|
2495
2646
|
}),
|
|
2496
|
-
tools: () =>
|
|
2647
|
+
tools: () => multiselect3({
|
|
2497
2648
|
message: "Which AI tools do you use?",
|
|
2498
2649
|
options: [
|
|
2499
2650
|
{ value: "copilot", label: "GitHub Copilot", hint: "VSCode" },
|
|
@@ -2505,28 +2656,28 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2505
2656
|
if (existingProjects.length === 0) {
|
|
2506
2657
|
return Promise.resolve([]);
|
|
2507
2658
|
}
|
|
2508
|
-
return
|
|
2659
|
+
return multiselect3({
|
|
2509
2660
|
message: "Link knowledge from other projects?",
|
|
2510
2661
|
options: existingProjects.map((project) => ({
|
|
2511
2662
|
value: `${project.name}:${project.source}`,
|
|
2512
2663
|
// Unique key
|
|
2513
|
-
label: `${project.name} ${
|
|
2514
|
-
hint:
|
|
2664
|
+
label: `${project.name} ${pc8.dim(`(${project.source})`)}`,
|
|
2665
|
+
hint: pc8.dim(
|
|
2515
2666
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
2516
2667
|
)
|
|
2517
2668
|
})),
|
|
2518
2669
|
required: false
|
|
2519
2670
|
});
|
|
2520
2671
|
},
|
|
2521
|
-
addToGitignore: () =>
|
|
2672
|
+
addToGitignore: () => confirm3({
|
|
2522
2673
|
message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
|
|
2523
2674
|
initialValue: true
|
|
2524
2675
|
}),
|
|
2525
|
-
confirm: () =>
|
|
2676
|
+
confirm: () => confirm3({
|
|
2526
2677
|
message: "Create configuration?",
|
|
2527
2678
|
initialValue: true
|
|
2528
2679
|
}),
|
|
2529
|
-
exposeToMCP: () =>
|
|
2680
|
+
exposeToMCP: () => confirm3({
|
|
2530
2681
|
message: "Expose this project to MCP (AI Agent) server?",
|
|
2531
2682
|
initialValue: true
|
|
2532
2683
|
})
|
|
@@ -2571,7 +2722,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2571
2722
|
`Storage: ${config.storageMode}`
|
|
2572
2723
|
];
|
|
2573
2724
|
if (customGlobalPath && customGlobalPath !== getDefaultRRCEHome()) {
|
|
2574
|
-
summary.push(`Global path: ${
|
|
2725
|
+
summary.push(`Global path: ${pc8.cyan(customGlobalPath)}`);
|
|
2575
2726
|
}
|
|
2576
2727
|
if (dataPaths.length > 0) {
|
|
2577
2728
|
summary.push(`Data paths:`);
|
|
@@ -2584,29 +2735,29 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2584
2735
|
const linkedProjects = config.linkedProjects;
|
|
2585
2736
|
if (linkedProjects.length > 0) {
|
|
2586
2737
|
summary.push(`Linked projects: ${linkedProjects.join(", ")}`);
|
|
2587
|
-
summary.push(`Workspace file: ${
|
|
2738
|
+
summary.push(`Workspace file: ${pc8.cyan(`${workspaceName}.code-workspace`)}`);
|
|
2588
2739
|
}
|
|
2589
|
-
|
|
2740
|
+
note7(summary.join("\n"), "Setup Summary");
|
|
2590
2741
|
if (config.exposeToMCP) {
|
|
2591
|
-
|
|
2742
|
+
note7(`${pc8.green("\u2713")} Project exposed to MCP Hub`, "MCP Configuration");
|
|
2592
2743
|
if (linkedProjects.length > 0) {
|
|
2593
|
-
outro2(
|
|
2744
|
+
outro2(pc8.green(`\u2713 Setup complete! Open ${pc8.bold(`${workspaceName}.code-workspace`)} in VSCode to access linked knowledge.`));
|
|
2594
2745
|
} else {
|
|
2595
|
-
outro2(
|
|
2746
|
+
outro2(pc8.green(`\u2713 Setup complete! Your agents are ready to use.`));
|
|
2596
2747
|
}
|
|
2597
2748
|
} else {
|
|
2598
|
-
const shouldConfigureMCP = await
|
|
2749
|
+
const shouldConfigureMCP = await confirm3({
|
|
2599
2750
|
message: "Would you like to configure the MCP server now?",
|
|
2600
2751
|
initialValue: true
|
|
2601
2752
|
});
|
|
2602
|
-
if (shouldConfigureMCP && !
|
|
2753
|
+
if (shouldConfigureMCP && !isCancel6(shouldConfigureMCP)) {
|
|
2603
2754
|
const { runMCP: runMCP2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
2604
2755
|
await runMCP2();
|
|
2605
2756
|
} else {
|
|
2606
2757
|
if (linkedProjects.length > 0) {
|
|
2607
|
-
outro2(
|
|
2758
|
+
outro2(pc8.green(`\u2713 Setup complete! Open ${pc8.bold(`${workspaceName}.code-workspace`)} in VSCode to access linked knowledge.`));
|
|
2608
2759
|
} else {
|
|
2609
|
-
outro2(
|
|
2760
|
+
outro2(pc8.green(`\u2713 Setup complete! Your agents are ready to use.`));
|
|
2610
2761
|
}
|
|
2611
2762
|
}
|
|
2612
2763
|
}
|
|
@@ -2770,8 +2921,8 @@ var init_setup_flow = __esm({
|
|
|
2770
2921
|
});
|
|
2771
2922
|
|
|
2772
2923
|
// src/commands/wizard/link-flow.ts
|
|
2773
|
-
import { multiselect as
|
|
2774
|
-
import
|
|
2924
|
+
import { multiselect as multiselect4, spinner as spinner4, note as note8, outro as outro3, cancel as cancel3, isCancel as isCancel7 } from "@clack/prompts";
|
|
2925
|
+
import pc9 from "picocolors";
|
|
2775
2926
|
import * as fs13 from "fs";
|
|
2776
2927
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
2777
2928
|
const projects = scanForProjects({
|
|
@@ -2779,23 +2930,23 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
2779
2930
|
workspacePath
|
|
2780
2931
|
});
|
|
2781
2932
|
if (projects.length === 0) {
|
|
2782
|
-
outro3(
|
|
2933
|
+
outro3(pc9.yellow("No other projects found. Try setting up another project first."));
|
|
2783
2934
|
return;
|
|
2784
2935
|
}
|
|
2785
2936
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2786
|
-
const linkedProjects = await
|
|
2937
|
+
const linkedProjects = await multiselect4({
|
|
2787
2938
|
message: "Select projects to link:",
|
|
2788
2939
|
options: projects.map((project) => ({
|
|
2789
2940
|
value: `${project.name}:${project.source}`,
|
|
2790
2941
|
// Unique key
|
|
2791
|
-
label: `${project.name} ${
|
|
2792
|
-
hint:
|
|
2942
|
+
label: `${project.name} ${pc9.dim(`(${project.source})`)}`,
|
|
2943
|
+
hint: pc9.dim(
|
|
2793
2944
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
2794
2945
|
)
|
|
2795
2946
|
})),
|
|
2796
2947
|
required: true
|
|
2797
2948
|
});
|
|
2798
|
-
if (
|
|
2949
|
+
if (isCancel7(linkedProjects)) {
|
|
2799
2950
|
cancel3("Cancelled.");
|
|
2800
2951
|
process.exit(0);
|
|
2801
2952
|
}
|
|
@@ -2807,7 +2958,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
2807
2958
|
const selectedProjects = projects.filter(
|
|
2808
2959
|
(p) => selectedKeys.includes(`${p.name}:${p.source}`)
|
|
2809
2960
|
);
|
|
2810
|
-
const s =
|
|
2961
|
+
const s = spinner4();
|
|
2811
2962
|
s.start("Linking projects");
|
|
2812
2963
|
const configFilePath = getConfigPath(workspacePath);
|
|
2813
2964
|
let configContent = fs13.readFileSync(configFilePath, "utf-8");
|
|
@@ -2843,12 +2994,12 @@ linked_projects:
|
|
|
2843
2994
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
2844
2995
|
const summary = [
|
|
2845
2996
|
`Linked projects:`,
|
|
2846
|
-
...selectedProjects.map((p) => ` \u2713 ${p.name} ${
|
|
2997
|
+
...selectedProjects.map((p) => ` \u2713 ${p.name} ${pc9.dim(`(${p.source})`)}`),
|
|
2847
2998
|
``,
|
|
2848
|
-
`Workspace file: ${
|
|
2999
|
+
`Workspace file: ${pc9.cyan(workspaceFile)}`
|
|
2849
3000
|
];
|
|
2850
|
-
|
|
2851
|
-
outro3(
|
|
3001
|
+
note8(summary.join("\n"), "Link Summary");
|
|
3002
|
+
outro3(pc9.green(`\u2713 Projects linked! Open ${pc9.bold(workspaceFile)} in VSCode to access linked data.`));
|
|
2852
3003
|
}
|
|
2853
3004
|
var init_link_flow = __esm({
|
|
2854
3005
|
"src/commands/wizard/link-flow.ts"() {
|
|
@@ -2860,8 +3011,8 @@ var init_link_flow = __esm({
|
|
|
2860
3011
|
});
|
|
2861
3012
|
|
|
2862
3013
|
// src/commands/wizard/sync-flow.ts
|
|
2863
|
-
import { confirm as
|
|
2864
|
-
import
|
|
3014
|
+
import { confirm as confirm4, spinner as spinner5, note as note9, outro as outro4, cancel as cancel4, isCancel as isCancel8 } from "@clack/prompts";
|
|
3015
|
+
import pc10 from "picocolors";
|
|
2865
3016
|
import * as fs14 from "fs";
|
|
2866
3017
|
import * as path13 from "path";
|
|
2867
3018
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
@@ -2873,25 +3024,25 @@ async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
|
2873
3024
|
(dir) => fs14.existsSync(path13.join(localPath, dir))
|
|
2874
3025
|
);
|
|
2875
3026
|
if (existingDirs.length === 0) {
|
|
2876
|
-
outro4(
|
|
3027
|
+
outro4(pc10.yellow("No data found in workspace storage to sync."));
|
|
2877
3028
|
return;
|
|
2878
3029
|
}
|
|
2879
|
-
|
|
3030
|
+
note9(
|
|
2880
3031
|
`The following will be copied to global storage:
|
|
2881
3032
|
${existingDirs.map((d) => ` \u2022 ${d}/`).join("\n")}
|
|
2882
3033
|
|
|
2883
|
-
Destination: ${
|
|
3034
|
+
Destination: ${pc10.cyan(globalPath)}`,
|
|
2884
3035
|
"Sync Preview"
|
|
2885
3036
|
);
|
|
2886
|
-
const shouldSync = await
|
|
3037
|
+
const shouldSync = await confirm4({
|
|
2887
3038
|
message: "Proceed with sync to global storage?",
|
|
2888
3039
|
initialValue: true
|
|
2889
3040
|
});
|
|
2890
|
-
if (
|
|
3041
|
+
if (isCancel8(shouldSync) || !shouldSync) {
|
|
2891
3042
|
outro4("Sync cancelled.");
|
|
2892
3043
|
return;
|
|
2893
3044
|
}
|
|
2894
|
-
const s =
|
|
3045
|
+
const s = spinner5();
|
|
2895
3046
|
s.start("Syncing to global storage");
|
|
2896
3047
|
try {
|
|
2897
3048
|
ensureDir(globalPath);
|
|
@@ -2906,12 +3057,12 @@ Destination: ${pc6.cyan(globalPath)}`,
|
|
|
2906
3057
|
`Synced directories:`,
|
|
2907
3058
|
...existingDirs.map((d) => ` \u2713 ${d}/`),
|
|
2908
3059
|
``,
|
|
2909
|
-
`Global path: ${
|
|
3060
|
+
`Global path: ${pc10.cyan(globalPath)}`,
|
|
2910
3061
|
``,
|
|
2911
3062
|
`Other projects can now link this knowledge!`
|
|
2912
3063
|
];
|
|
2913
|
-
|
|
2914
|
-
outro4(
|
|
3064
|
+
note9(summary.join("\n"), "Sync Summary");
|
|
3065
|
+
outro4(pc10.green("\u2713 Workspace knowledge synced to global storage!"));
|
|
2915
3066
|
} catch (error) {
|
|
2916
3067
|
s.stop("Error occurred");
|
|
2917
3068
|
cancel4(`Failed to sync: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -2927,12 +3078,12 @@ var init_sync_flow = __esm({
|
|
|
2927
3078
|
});
|
|
2928
3079
|
|
|
2929
3080
|
// src/commands/wizard/update-flow.ts
|
|
2930
|
-
import { confirm as
|
|
2931
|
-
import
|
|
3081
|
+
import { confirm as confirm5, spinner as spinner6, note as note10, outro as outro5, cancel as cancel5, isCancel as isCancel9 } from "@clack/prompts";
|
|
3082
|
+
import pc11 from "picocolors";
|
|
2932
3083
|
import * as fs15 from "fs";
|
|
2933
3084
|
import * as path14 from "path";
|
|
2934
3085
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
2935
|
-
const s =
|
|
3086
|
+
const s = spinner6();
|
|
2936
3087
|
s.start("Checking for updates");
|
|
2937
3088
|
try {
|
|
2938
3089
|
const agentCoreDir = getAgentCoreDir();
|
|
@@ -2941,7 +3092,7 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
|
2941
3092
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2942
3093
|
const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
|
|
2943
3094
|
s.stop("Updates found");
|
|
2944
|
-
|
|
3095
|
+
note10(
|
|
2945
3096
|
`The following will be updated from the package:
|
|
2946
3097
|
\u2022 prompts/ (${prompts.length} agent prompts)
|
|
2947
3098
|
\u2022 templates/ (output templates)
|
|
@@ -2950,11 +3101,11 @@ Target locations:
|
|
|
2950
3101
|
${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
2951
3102
|
"Update Preview"
|
|
2952
3103
|
);
|
|
2953
|
-
const shouldUpdate = await
|
|
3104
|
+
const shouldUpdate = await confirm5({
|
|
2954
3105
|
message: "Proceed with update?",
|
|
2955
3106
|
initialValue: true
|
|
2956
3107
|
});
|
|
2957
|
-
if (
|
|
3108
|
+
if (isCancel9(shouldUpdate) || !shouldUpdate) {
|
|
2958
3109
|
outro5("Update cancelled.");
|
|
2959
3110
|
return;
|
|
2960
3111
|
}
|
|
@@ -2982,8 +3133,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
2982
3133
|
``,
|
|
2983
3134
|
`Your configuration and knowledge files were preserved.`
|
|
2984
3135
|
];
|
|
2985
|
-
|
|
2986
|
-
outro5(
|
|
3136
|
+
note10(summary.join("\n"), "Update Summary");
|
|
3137
|
+
outro5(pc11.green("\u2713 Successfully updated from package!"));
|
|
2987
3138
|
} catch (error) {
|
|
2988
3139
|
s.stop("Error occurred");
|
|
2989
3140
|
cancel5(`Failed to update: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -3016,21 +3167,21 @@ var wizard_exports = {};
|
|
|
3016
3167
|
__export(wizard_exports, {
|
|
3017
3168
|
runWizard: () => runWizard
|
|
3018
3169
|
});
|
|
3019
|
-
import { intro as intro2, select as select4, spinner as
|
|
3020
|
-
import
|
|
3170
|
+
import { intro as intro2, select as select4, spinner as spinner7, note as note11, outro as outro6, isCancel as isCancel10 } from "@clack/prompts";
|
|
3171
|
+
import pc12 from "picocolors";
|
|
3021
3172
|
import * as fs16 from "fs";
|
|
3022
3173
|
async function runWizard() {
|
|
3023
|
-
intro2(
|
|
3024
|
-
const s =
|
|
3174
|
+
intro2(pc12.cyan(pc12.inverse(" RRCE-Workflow Setup ")));
|
|
3175
|
+
const s = spinner7();
|
|
3025
3176
|
s.start("Detecting environment");
|
|
3026
3177
|
const workspacePath = detectWorkspaceRoot();
|
|
3027
3178
|
const workspaceName = getWorkspaceName(workspacePath);
|
|
3028
3179
|
const gitUser = getGitUser();
|
|
3029
3180
|
await new Promise((r) => setTimeout(r, 800));
|
|
3030
3181
|
s.stop("Environment detected");
|
|
3031
|
-
|
|
3032
|
-
`Git User: ${
|
|
3033
|
-
Workspace: ${
|
|
3182
|
+
note11(
|
|
3183
|
+
`Git User: ${pc12.bold(gitUser || "(not found)")}
|
|
3184
|
+
Workspace: ${pc12.bold(workspaceName)}`,
|
|
3034
3185
|
"Context"
|
|
3035
3186
|
);
|
|
3036
3187
|
const detectedProjects = scanForProjects({
|
|
@@ -3077,7 +3228,7 @@ Workspace: ${pc8.bold(workspaceName)}`,
|
|
|
3077
3228
|
message: "This workspace is already configured. What would you like to do?",
|
|
3078
3229
|
options: menuOptions
|
|
3079
3230
|
});
|
|
3080
|
-
if (
|
|
3231
|
+
if (isCancel10(action) || action === "exit") {
|
|
3081
3232
|
outro6("Exited.");
|
|
3082
3233
|
process.exit(0);
|
|
3083
3234
|
}
|
|
@@ -3119,12 +3270,12 @@ init_wizard();
|
|
|
3119
3270
|
|
|
3120
3271
|
// src/commands/selector.ts
|
|
3121
3272
|
init_prompts();
|
|
3122
|
-
import { intro as intro3, select as select5, note as
|
|
3123
|
-
import
|
|
3273
|
+
import { intro as intro3, select as select5, note as note12, cancel as cancel7, isCancel as isCancel11, outro as outro7 } from "@clack/prompts";
|
|
3274
|
+
import pc13 from "picocolors";
|
|
3124
3275
|
import * as path15 from "path";
|
|
3125
3276
|
async function runSelector() {
|
|
3126
3277
|
const workspaceName = path15.basename(process.cwd());
|
|
3127
|
-
intro3(
|
|
3278
|
+
intro3(pc13.cyan(pc13.inverse(` RRCE-Workflow | ${workspaceName} `)));
|
|
3128
3279
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
3129
3280
|
if (prompts.length === 0) {
|
|
3130
3281
|
cancel7("No agents found. Run `rrce-workflow` to set up.");
|
|
@@ -3150,7 +3301,7 @@ async function runSelector() {
|
|
|
3150
3301
|
}))
|
|
3151
3302
|
]
|
|
3152
3303
|
});
|
|
3153
|
-
if (
|
|
3304
|
+
if (isCancel11(selection)) {
|
|
3154
3305
|
cancel7("Selection cancelled.");
|
|
3155
3306
|
process.exit(0);
|
|
3156
3307
|
}
|
|
@@ -3165,9 +3316,9 @@ async function runSelector() {
|
|
|
3165
3316
|
return;
|
|
3166
3317
|
}
|
|
3167
3318
|
const prompt = selection;
|
|
3168
|
-
|
|
3319
|
+
note12(
|
|
3169
3320
|
`Use this agent in your IDE by invoking:
|
|
3170
|
-
${
|
|
3321
|
+
${pc13.bold(pc13.cyan(`@${prompt.frontmatter.name}`))}`,
|
|
3171
3322
|
"Agent Selected"
|
|
3172
3323
|
);
|
|
3173
3324
|
outro7("Done");
|