rrce-workflow 0.2.26 → 0.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +493 -180
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -583,7 +583,7 @@ var init_types = __esm({
583
583
  });
584
584
 
585
585
  // src/mcp/config.ts
586
- import * as fs12 from "fs";
586
+ import * as fs11 from "fs";
587
587
  import * as path11 from "path";
588
588
  function getMCPConfigPath() {
589
589
  const workspaceRoot = detectWorkspaceRoot();
@@ -595,8 +595,8 @@ function ensureMCPGlobalPath() {
595
595
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
596
596
  if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
597
597
  const configPath = path11.join(workspaceRoot, ".rrce-workflow", "config.yaml");
598
- if (fs12.existsSync(configPath)) {
599
- const content = fs12.readFileSync(configPath, "utf-8");
598
+ if (fs11.existsSync(configPath)) {
599
+ const content = fs11.readFileSync(configPath, "utf-8");
600
600
  const modeMatch = content.match(/mode:\s*(global|workspace)/);
601
601
  if (modeMatch?.[1] === "workspace") {
602
602
  return {
@@ -614,11 +614,11 @@ function ensureMCPGlobalPath() {
614
614
  }
615
615
  function loadMCPConfig() {
616
616
  const configPath = getMCPConfigPath();
617
- if (!fs12.existsSync(configPath)) {
617
+ if (!fs11.existsSync(configPath)) {
618
618
  return { ...DEFAULT_MCP_CONFIG };
619
619
  }
620
620
  try {
621
- const content = fs12.readFileSync(configPath, "utf-8");
621
+ const content = fs11.readFileSync(configPath, "utf-8");
622
622
  return parseMCPConfig(content);
623
623
  } catch {
624
624
  return { ...DEFAULT_MCP_CONFIG };
@@ -627,11 +627,11 @@ function loadMCPConfig() {
627
627
  function saveMCPConfig(config) {
628
628
  const configPath = getMCPConfigPath();
629
629
  const dir = path11.dirname(configPath);
630
- if (!fs12.existsSync(dir)) {
631
- fs12.mkdirSync(dir, { recursive: true });
630
+ if (!fs11.existsSync(dir)) {
631
+ fs11.mkdirSync(dir, { recursive: true });
632
632
  }
633
633
  const content = serializeMCPConfig(config);
634
- fs12.writeFileSync(configPath, content);
634
+ fs11.writeFileSync(configPath, content);
635
635
  }
636
636
  function parseMCPConfig(content) {
637
637
  const config = { ...DEFAULT_MCP_CONFIG, projects: [] };
@@ -794,7 +794,7 @@ __export(logger_exports, {
794
794
  getLogFilePath: () => getLogFilePath,
795
795
  logger: () => logger
796
796
  });
797
- import * as fs13 from "fs";
797
+ import * as fs12 from "fs";
798
798
  import * as path12 from "path";
799
799
  function getLogFilePath() {
800
800
  const workspaceRoot = detectWorkspaceRoot();
@@ -831,10 +831,10 @@ ${JSON.stringify(data, null, 2)}`;
831
831
  logMessage += "\n";
832
832
  try {
833
833
  const dir = path12.dirname(this.logPath);
834
- if (!fs13.existsSync(dir)) {
835
- fs13.mkdirSync(dir, { recursive: true });
834
+ if (!fs12.existsSync(dir)) {
835
+ fs12.mkdirSync(dir, { recursive: true });
836
836
  }
837
- fs13.appendFileSync(this.logPath, logMessage);
837
+ fs12.appendFileSync(this.logPath, logMessage);
838
838
  } catch (e) {
839
839
  console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
840
840
  console.error(logMessage);
@@ -858,7 +858,7 @@ ${JSON.stringify(data, null, 2)}`;
858
858
  });
859
859
 
860
860
  // src/mcp/resources.ts
861
- import * as fs14 from "fs";
861
+ import * as fs13 from "fs";
862
862
  import * as path13 from "path";
863
863
  function getExposedProjects() {
864
864
  const config = loadMCPConfig();
@@ -887,10 +887,10 @@ function getProjectContext(projectName) {
887
887
  return null;
888
888
  }
889
889
  const contextPath = path13.join(project.knowledgePath, "project-context.md");
890
- if (!fs14.existsSync(contextPath)) {
890
+ if (!fs13.existsSync(contextPath)) {
891
891
  return null;
892
892
  }
893
- return fs14.readFileSync(contextPath, "utf-8");
893
+ return fs13.readFileSync(contextPath, "utf-8");
894
894
  }
895
895
  function getProjectTasks(projectName) {
896
896
  const config = loadMCPConfig();
@@ -903,18 +903,18 @@ function getProjectTasks(projectName) {
903
903
  }
904
904
  const projects = scanForProjects();
905
905
  const project = projects.find((p) => p.name === projectName);
906
- if (!project?.tasksPath || !fs14.existsSync(project.tasksPath)) {
906
+ if (!project?.tasksPath || !fs13.existsSync(project.tasksPath)) {
907
907
  return [];
908
908
  }
909
909
  const tasks = [];
910
910
  try {
911
- const taskDirs = fs14.readdirSync(project.tasksPath, { withFileTypes: true });
911
+ const taskDirs = fs13.readdirSync(project.tasksPath, { withFileTypes: true });
912
912
  for (const dir of taskDirs) {
913
913
  if (!dir.isDirectory()) continue;
914
914
  const metaPath = path13.join(project.tasksPath, dir.name, "meta.json");
915
- if (fs14.existsSync(metaPath)) {
915
+ if (fs13.existsSync(metaPath)) {
916
916
  try {
917
- const meta = JSON.parse(fs14.readFileSync(metaPath, "utf-8"));
917
+ const meta = JSON.parse(fs13.readFileSync(metaPath, "utf-8"));
918
918
  tasks.push(meta);
919
919
  } catch {
920
920
  }
@@ -933,11 +933,11 @@ function searchKnowledge(query) {
933
933
  const permissions = getProjectPermissions(config, project.name);
934
934
  if (!permissions.knowledge || !project.knowledgePath) continue;
935
935
  try {
936
- const files = fs14.readdirSync(project.knowledgePath);
936
+ const files = fs13.readdirSync(project.knowledgePath);
937
937
  for (const file of files) {
938
938
  if (!file.endsWith(".md")) continue;
939
939
  const filePath = path13.join(project.knowledgePath, file);
940
- const content = fs14.readFileSync(filePath, "utf-8");
940
+ const content = fs13.readFileSync(filePath, "utf-8");
941
941
  const lines = content.split("\n");
942
942
  const matches = [];
943
943
  for (const line of lines) {
@@ -1149,6 +1149,23 @@ function registerToolHandlers(server) {
1149
1149
  properties: { project: { type: "string", description: "Name of the project to get context for" } },
1150
1150
  required: ["project"]
1151
1151
  }
1152
+ },
1153
+ {
1154
+ name: "list_agents",
1155
+ description: "List available RRCE agents/workflows",
1156
+ inputSchema: { type: "object", properties: {} }
1157
+ },
1158
+ {
1159
+ name: "get_agent_prompt",
1160
+ description: "Get the instructions/prompt for a specific agent",
1161
+ inputSchema: {
1162
+ type: "object",
1163
+ properties: {
1164
+ agent: { type: "string", description: "Name of the agent (e.g. init, plan, execute)" },
1165
+ args: { type: "object", description: "Arguments for the agent prompt", additionalProperties: true }
1166
+ },
1167
+ required: ["agent"]
1168
+ }
1152
1169
  }
1153
1170
  ]
1154
1171
  }));
@@ -1179,6 +1196,56 @@ function registerToolHandlers(server) {
1179
1196
  }
1180
1197
  return { content: [{ type: "text", text: context }] };
1181
1198
  }
1199
+ case "list_agents": {
1200
+ const prompts = getAllPrompts();
1201
+ return {
1202
+ content: [{
1203
+ type: "text",
1204
+ text: JSON.stringify(prompts.map((p) => ({
1205
+ name: p.name,
1206
+ description: p.description,
1207
+ arguments: p.arguments
1208
+ })), null, 2)
1209
+ }]
1210
+ };
1211
+ }
1212
+ case "get_agent_prompt": {
1213
+ const params = args;
1214
+ const agentName = params.agent;
1215
+ const promptDef = getPromptDef(agentName);
1216
+ if (!promptDef) {
1217
+ throw new Error(`Agent not found: ${agentName}`);
1218
+ }
1219
+ const renderArgs = params.args || {};
1220
+ const stringArgs = {};
1221
+ for (const [key, val] of Object.entries(renderArgs)) {
1222
+ stringArgs[key] = String(val);
1223
+ }
1224
+ const content = renderPrompt(promptDef.content, stringArgs);
1225
+ const projects = getExposedProjects();
1226
+ const activeProject = detectActiveProject();
1227
+ const projectList = projects.map((p) => {
1228
+ const isActive = activeProject && p.dataPath === activeProject.dataPath;
1229
+ return `- ${p.name} (${p.source}) ${isActive ? "**[ACTIVE]**" : ""}`;
1230
+ }).join("\n");
1231
+ let contextPreamble = `
1232
+ Context - Available Projects (MCP Hub):
1233
+ ${projectList}
1234
+ `;
1235
+ if (activeProject) {
1236
+ contextPreamble += `
1237
+ Current Active Workspace: ${activeProject.name} (${activeProject.path})
1238
+ `;
1239
+ contextPreamble += `IMPORTANT: Treat '${activeProject.path}' as the {{WORKSPACE_ROOT}}. All relative path operations (file reads/writes) MUST be performed relative to this directory.
1240
+ `;
1241
+ }
1242
+ contextPreamble += `
1243
+ Note: If the user's request refers to a project not listed here, ask them to expose it via 'rrce-workflow mcp configure'.
1244
+
1245
+ ---
1246
+ `;
1247
+ return { content: [{ type: "text", text: contextPreamble + content }] };
1248
+ }
1182
1249
  default:
1183
1250
  throw new Error(`Unknown tool: ${name}`);
1184
1251
  }
@@ -1290,34 +1357,81 @@ var init_server = __esm({
1290
1357
  });
1291
1358
 
1292
1359
  // src/mcp/install.ts
1293
- import * as fs15 from "fs";
1360
+ import * as fs14 from "fs";
1294
1361
  import * as path14 from "path";
1295
1362
  import * as os from "os";
1296
- function checkInstallStatus() {
1363
+ function checkInstallStatus(workspacePath) {
1297
1364
  return {
1298
- antigravity: checkConfigFile(ANTIGRAVITY_CONFIG),
1299
- claude: checkConfigFile(CLAUDE_CONFIG)
1365
+ antigravity: checkAntigravityConfig(),
1366
+ claude: checkClaudeConfig(),
1367
+ vscodeGlobal: checkVSCodeGlobalConfig(),
1368
+ vscodeWorkspace: workspacePath ? checkVSCodeWorkspaceConfig(workspacePath) : false
1300
1369
  };
1301
1370
  }
1302
- function checkConfigFile(configPath) {
1303
- if (!fs15.existsSync(configPath)) return false;
1371
+ function checkAntigravityConfig() {
1372
+ if (!fs14.existsSync(ANTIGRAVITY_CONFIG)) return false;
1304
1373
  try {
1305
- const content = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
1374
+ const content = JSON.parse(fs14.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
1306
1375
  return !!content.mcpServers?.["rrce"];
1307
1376
  } catch {
1308
1377
  return false;
1309
1378
  }
1310
1379
  }
1311
- function installToConfig(target) {
1312
- const configPath = target === "antigravity" ? ANTIGRAVITY_CONFIG : CLAUDE_CONFIG;
1313
- const dir = path14.dirname(configPath);
1314
- if (!fs15.existsSync(dir)) {
1315
- fs15.mkdirSync(dir, { recursive: true });
1380
+ function checkClaudeConfig() {
1381
+ if (!fs14.existsSync(CLAUDE_CONFIG)) return false;
1382
+ try {
1383
+ const content = JSON.parse(fs14.readFileSync(CLAUDE_CONFIG, "utf-8"));
1384
+ return !!content.mcpServers?.["rrce"];
1385
+ } catch {
1386
+ return false;
1387
+ }
1388
+ }
1389
+ function checkVSCodeGlobalConfig() {
1390
+ if (!fs14.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
1391
+ try {
1392
+ const content = JSON.parse(fs14.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
1393
+ return !!content["mcp.servers"]?.["rrce"];
1394
+ } catch {
1395
+ return false;
1396
+ }
1397
+ }
1398
+ function checkVSCodeWorkspaceConfig(workspacePath) {
1399
+ const configPath = path14.join(workspacePath, ".vscode", "mcp.json");
1400
+ if (!fs14.existsSync(configPath)) return false;
1401
+ try {
1402
+ const content = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
1403
+ return !!content.servers?.["rrce"];
1404
+ } catch {
1405
+ return false;
1406
+ }
1407
+ }
1408
+ function isInstalledAnywhere(workspacePath) {
1409
+ const status = checkInstallStatus(workspacePath);
1410
+ return status.antigravity || status.claude || status.vscodeGlobal || status.vscodeWorkspace;
1411
+ }
1412
+ function installToConfig(target, workspacePath) {
1413
+ switch (target) {
1414
+ case "antigravity":
1415
+ return installToAntigravity();
1416
+ case "claude":
1417
+ return installToClaude();
1418
+ case "vscode-global":
1419
+ return installToVSCodeGlobal();
1420
+ case "vscode-workspace":
1421
+ return workspacePath ? installToVSCodeWorkspace(workspacePath) : false;
1422
+ default:
1423
+ return false;
1424
+ }
1425
+ }
1426
+ function installToAntigravity() {
1427
+ const dir = path14.dirname(ANTIGRAVITY_CONFIG);
1428
+ if (!fs14.existsSync(dir)) {
1429
+ fs14.mkdirSync(dir, { recursive: true });
1316
1430
  }
1317
1431
  let config = { mcpServers: {} };
1318
- if (fs15.existsSync(configPath)) {
1432
+ if (fs14.existsSync(ANTIGRAVITY_CONFIG)) {
1319
1433
  try {
1320
- config = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
1434
+ config = JSON.parse(fs14.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
1321
1435
  } catch {
1322
1436
  }
1323
1437
  }
@@ -1325,21 +1439,108 @@ function installToConfig(target) {
1325
1439
  config.mcpServers["rrce"] = {
1326
1440
  command: "npx",
1327
1441
  args: ["-y", "rrce-workflow", "mcp", "start"]
1328
- // -y to avoid interactive prompts
1329
1442
  };
1330
1443
  try {
1331
- fs15.writeFileSync(configPath, JSON.stringify(config, null, 2));
1444
+ fs14.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
1445
+ return true;
1446
+ } catch {
1447
+ return false;
1448
+ }
1449
+ }
1450
+ function installToClaude() {
1451
+ const dir = path14.dirname(CLAUDE_CONFIG);
1452
+ if (!fs14.existsSync(dir)) {
1453
+ fs14.mkdirSync(dir, { recursive: true });
1454
+ }
1455
+ let config = { mcpServers: {} };
1456
+ if (fs14.existsSync(CLAUDE_CONFIG)) {
1457
+ try {
1458
+ config = JSON.parse(fs14.readFileSync(CLAUDE_CONFIG, "utf-8"));
1459
+ } catch {
1460
+ }
1461
+ }
1462
+ if (!config.mcpServers) config.mcpServers = {};
1463
+ config.mcpServers["rrce"] = {
1464
+ command: "npx",
1465
+ args: ["-y", "rrce-workflow", "mcp", "start"]
1466
+ };
1467
+ try {
1468
+ fs14.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
1469
+ return true;
1470
+ } catch {
1471
+ return false;
1472
+ }
1473
+ }
1474
+ function installToVSCodeGlobal() {
1475
+ const dir = path14.dirname(VSCODE_GLOBAL_CONFIG);
1476
+ if (!fs14.existsSync(dir)) {
1477
+ fs14.mkdirSync(dir, { recursive: true });
1478
+ }
1479
+ let settings = {};
1480
+ if (fs14.existsSync(VSCODE_GLOBAL_CONFIG)) {
1481
+ try {
1482
+ settings = JSON.parse(fs14.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
1483
+ } catch {
1484
+ }
1485
+ }
1486
+ if (!settings["mcp.servers"]) settings["mcp.servers"] = {};
1487
+ settings["mcp.servers"]["rrce"] = {
1488
+ command: "npx",
1489
+ args: ["-y", "rrce-workflow", "mcp", "start"]
1490
+ };
1491
+ try {
1492
+ fs14.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
1332
1493
  return true;
1333
1494
  } catch {
1334
1495
  return false;
1335
1496
  }
1336
1497
  }
1337
- var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG;
1498
+ function installToVSCodeWorkspace(workspacePath) {
1499
+ const vscodeDir = path14.join(workspacePath, ".vscode");
1500
+ const configPath = path14.join(vscodeDir, "mcp.json");
1501
+ if (!fs14.existsSync(vscodeDir)) {
1502
+ fs14.mkdirSync(vscodeDir, { recursive: true });
1503
+ }
1504
+ let config = { servers: {} };
1505
+ if (fs14.existsSync(configPath)) {
1506
+ try {
1507
+ config = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
1508
+ } catch {
1509
+ }
1510
+ }
1511
+ if (!config.servers) config.servers = {};
1512
+ config.servers["rrce"] = {
1513
+ command: "npx",
1514
+ args: ["-y", "rrce-workflow", "mcp", "start"]
1515
+ };
1516
+ try {
1517
+ fs14.writeFileSync(configPath, JSON.stringify(config, null, 2));
1518
+ return true;
1519
+ } catch {
1520
+ return false;
1521
+ }
1522
+ }
1523
+ function getTargetLabel(target) {
1524
+ switch (target) {
1525
+ case "antigravity":
1526
+ return "Antigravity IDE";
1527
+ case "claude":
1528
+ return "Claude Desktop";
1529
+ case "vscode-global":
1530
+ return "VSCode (Global)";
1531
+ case "vscode-workspace":
1532
+ return "VSCode (Workspace)";
1533
+ default:
1534
+ return target;
1535
+ }
1536
+ }
1537
+ var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG;
1338
1538
  var init_install = __esm({
1339
1539
  "src/mcp/install.ts"() {
1340
1540
  "use strict";
1341
1541
  ANTIGRAVITY_CONFIG = path14.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
1342
1542
  CLAUDE_CONFIG = path14.join(os.homedir(), ".config/claude/claude_desktop_config.json");
1543
+ VSCODE_GLOBAL_CONFIG = path14.join(os.homedir(), ".config/Code/User/settings.json");
1343
1544
  }
1344
1545
  });
1345
1546
 
@@ -1348,8 +1549,8 @@ var mcp_exports = {};
1348
1549
  __export(mcp_exports, {
1349
1550
  runMCP: () => runMCP
1350
1551
  });
1351
- import { intro as intro2, outro as outro6, select as select4, multiselect as multiselect3, confirm as confirm4, spinner as spinner6, note as note7, cancel as cancel6, isCancel as isCancel7, text as text2 } from "@clack/prompts";
1352
- import pc8 from "picocolors";
1552
+ import { intro, outro as outro5, select as select3, multiselect as multiselect3, confirm as confirm4, spinner as spinner5, note as note6, cancel as cancel5, isCancel as isCancel6, text as text2 } from "@clack/prompts";
1553
+ import pc7 from "picocolors";
1353
1554
  async function runMCP(subcommand2) {
1354
1555
  if (subcommand2) {
1355
1556
  switch (subcommand2) {
@@ -1369,42 +1570,69 @@ async function runMCP(subcommand2) {
1369
1570
  return;
1370
1571
  }
1371
1572
  }
1372
- intro2(pc8.bgCyan(pc8.black(" RRCE MCP Hub ")));
1573
+ intro(pc7.bgCyan(pc7.black(" RRCE MCP Hub ")));
1574
+ const workspacePath = detectWorkspaceRoot();
1373
1575
  const globalPathCheck = await ensureMCPGlobalPath();
1374
1576
  if (!globalPathCheck.configured) {
1375
1577
  const configured = await handleConfigureGlobalPath();
1376
1578
  if (!configured) {
1377
- outro6(pc8.yellow("MCP requires a global storage path. Setup cancelled."));
1579
+ outro5(pc7.yellow("MCP requires a global storage path. Setup cancelled."));
1378
1580
  return;
1379
1581
  }
1380
1582
  }
1381
- const status = checkInstallStatus();
1382
- if (!status.antigravity && !status.claude) {
1583
+ const status = checkInstallStatus(workspacePath);
1584
+ const installed = isInstalledAnywhere(workspacePath);
1585
+ if (!installed) {
1586
+ note6(
1587
+ `${pc7.bold("Welcome to RRCE MCP Hub!")}
1588
+
1589
+ MCP (Model Context Protocol) allows AI assistants to access your
1590
+ project knowledge in real-time. Let's get you set up.`,
1591
+ "Getting Started"
1592
+ );
1383
1593
  const shouldInstall = await confirm4({
1384
- message: "MCP server is not installed in your IDEs. Install now?",
1594
+ message: "Install MCP server to your IDE(s)?",
1385
1595
  initialValue: true
1386
1596
  });
1387
- if (shouldInstall && !isCancel7(shouldInstall)) {
1388
- await handleInstallWizard();
1597
+ if (shouldInstall && !isCancel6(shouldInstall)) {
1598
+ await handleInstallWizard(workspacePath);
1599
+ await handleConfigure();
1600
+ const shouldStart = await confirm4({
1601
+ message: "Start the MCP server now?",
1602
+ initialValue: true
1603
+ });
1604
+ if (shouldStart && !isCancel6(shouldStart)) {
1605
+ await handleStartServer();
1606
+ }
1389
1607
  }
1608
+ outro5(pc7.green("MCP Hub setup complete!"));
1609
+ return;
1610
+ }
1611
+ const config = loadMCPConfig();
1612
+ const exposedCount = config.projects.filter((p) => p.expose).length;
1613
+ if (exposedCount === 0 && !config.defaults.includeNew) {
1614
+ note6("MCP is installed but no projects are exposed. Let's configure that.", "Configuration Needed");
1615
+ await handleConfigure();
1390
1616
  }
1391
1617
  let running = true;
1392
1618
  while (running) {
1393
1619
  const serverStatus = getMCPServerStatus();
1394
- const serverLabel = serverStatus.running ? pc8.green("Running") : pc8.dim("Stopped");
1395
- const action = await select4({
1620
+ const serverLabel = serverStatus.running ? pc7.green("\u25CF Running") : pc7.dim("\u25CB Stopped");
1621
+ const currentStatus = checkInstallStatus(workspacePath);
1622
+ const installedCount = [currentStatus.antigravity, currentStatus.claude, currentStatus.vscodeGlobal, currentStatus.vscodeWorkspace].filter(Boolean).length;
1623
+ const action = await select3({
1396
1624
  message: "What would you like to do?",
1397
1625
  options: [
1398
- { value: "start", label: `\u25B6\uFE0F Start MCP server`, hint: `Current status: ${serverLabel}` },
1626
+ { value: "start", label: `\u25B6\uFE0F Start MCP server`, hint: serverLabel },
1399
1627
  { value: "configure", label: "\u2699\uFE0F Configure projects", hint: "Choose which projects to expose" },
1400
- { value: "install", label: "\u{1F4E5} Install to IDE", hint: "Add to Antigravity or Claude Desktop" },
1628
+ { value: "install", label: "\u{1F4E5} Install to IDE", hint: `${installedCount} IDE(s) configured` },
1401
1629
  { value: "status", label: "\u{1F4CB} View status", hint: "See details" },
1402
1630
  { value: "help", label: "\u2753 Help", hint: "Learn about MCP Hub" },
1403
1631
  { value: "exit", label: "\u21A9 Exit", hint: "Return to shell" }
1404
1632
  ]
1405
1633
  });
1406
- if (isCancel7(action)) {
1407
- cancel6("MCP Hub closed.");
1634
+ if (isCancel6(action)) {
1635
+ cancel5("MCP Hub closed.");
1408
1636
  return;
1409
1637
  }
1410
1638
  switch (action) {
@@ -1415,7 +1643,7 @@ async function runMCP(subcommand2) {
1415
1643
  await handleConfigure();
1416
1644
  break;
1417
1645
  case "install":
1418
- await handleInstallWizard();
1646
+ await handleInstallWizard(workspacePath);
1419
1647
  break;
1420
1648
  case "status":
1421
1649
  await handleShowStatus();
@@ -1428,46 +1656,72 @@ async function runMCP(subcommand2) {
1428
1656
  break;
1429
1657
  }
1430
1658
  }
1431
- outro6(pc8.green("MCP Hub closed."));
1659
+ outro5(pc7.green("MCP Hub closed."));
1432
1660
  }
1433
- async function handleInstallWizard() {
1434
- const status = checkInstallStatus();
1661
+ async function handleInstallWizard(workspacePath) {
1662
+ const status = checkInstallStatus(workspacePath);
1435
1663
  const options = [
1436
- { value: "antigravity", label: "Antigravity IDE", hint: status.antigravity ? "Installed" : "Not installed" },
1437
- { value: "claude", label: "Claude Desktop", hint: status.claude ? "Installed" : "Not installed" }
1664
+ {
1665
+ value: "antigravity",
1666
+ label: "Antigravity IDE",
1667
+ hint: status.antigravity ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")
1668
+ },
1669
+ {
1670
+ value: "vscode-global",
1671
+ label: "VSCode (Global)",
1672
+ hint: status.vscodeGlobal ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")
1673
+ },
1674
+ {
1675
+ value: "vscode-workspace",
1676
+ label: "VSCode (This Workspace)",
1677
+ hint: status.vscodeWorkspace ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")
1678
+ },
1679
+ {
1680
+ value: "claude",
1681
+ label: "Claude Desktop",
1682
+ hint: status.claude ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")
1683
+ }
1438
1684
  ];
1439
1685
  const selected = await multiselect3({
1440
1686
  message: "Select where to install RRCE MCP Server:",
1441
1687
  options,
1442
1688
  initialValues: [
1443
1689
  ...status.antigravity ? ["antigravity"] : [],
1690
+ ...status.vscodeGlobal ? ["vscode-global"] : [],
1691
+ ...status.vscodeWorkspace ? ["vscode-workspace"] : [],
1444
1692
  ...status.claude ? ["claude"] : []
1445
1693
  ],
1446
1694
  required: false
1447
1695
  });
1448
- if (isCancel7(selected)) return;
1696
+ if (isCancel6(selected)) return;
1449
1697
  const targets = selected;
1450
1698
  const results = [];
1451
1699
  for (const target of targets) {
1452
- const success = installToConfig(target);
1453
- results.push(`${target}: ${success ? pc8.green("Success") : pc8.red("Failed")}`);
1700
+ const success = installToConfig(target, workspacePath);
1701
+ const label = getTargetLabel(target);
1702
+ results.push(`${label}: ${success ? pc7.green("\u2713 Success") : pc7.red("\u2717 Failed")}`);
1454
1703
  }
1455
1704
  if (results.length > 0) {
1456
- note7(results.join("\n"), "Installation Results");
1705
+ note6(results.join("\n"), "Installation Results");
1457
1706
  }
1458
1707
  }
1459
1708
  async function handleStartServer() {
1460
1709
  const fs16 = await import("fs");
1461
1710
  const { getLogFilePath: getLogFilePath2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
1462
1711
  const config = loadMCPConfig();
1463
- const exposedCount = config.projects.filter((p) => p.expose).length;
1464
- if (exposedCount === 0 && !config.defaults.includeNew) {
1712
+ const projects = scanForProjects();
1713
+ const exposedProjects = projects.filter((p) => {
1714
+ const cfg = config.projects.find((c) => c.name === p.name);
1715
+ return cfg?.expose ?? config.defaults.includeNew;
1716
+ });
1717
+ if (exposedProjects.length === 0) {
1465
1718
  const shouldConfig = await confirm4({
1466
1719
  message: "No projects are currently exposed. Configure now?",
1467
1720
  initialValue: true
1468
1721
  });
1469
- if (shouldConfig && !isCancel7(shouldConfig)) {
1722
+ if (shouldConfig && !isCancel6(shouldConfig)) {
1470
1723
  await handleConfigure();
1724
+ return handleStartServer();
1471
1725
  }
1472
1726
  }
1473
1727
  const portInput = await text2({
@@ -1478,7 +1732,7 @@ async function handleStartServer() {
1478
1732
  if (isNaN(Number(value))) return "Port must be a number";
1479
1733
  }
1480
1734
  });
1481
- if (isCancel7(portInput)) return;
1735
+ if (isCancel6(portInput)) return;
1482
1736
  const newPort = parseInt(portInput, 10);
1483
1737
  if (newPort !== config.server.port) {
1484
1738
  config.server.port = newPort;
@@ -1486,23 +1740,33 @@ async function handleStartServer() {
1486
1740
  }
1487
1741
  console.clear();
1488
1742
  const logPath = getLogFilePath2();
1489
- const renderHeader = () => {
1743
+ const workspacePath = detectWorkspaceRoot();
1744
+ const exposedNames = exposedProjects.map((p) => p.name).slice(0, 5);
1745
+ const exposedLabel = exposedNames.length > 0 ? exposedNames.join(", ") + (exposedProjects.length > 5 ? ` (+${exposedProjects.length - 5} more)` : "") : pc7.dim("(none)");
1746
+ const render = (logs = []) => {
1490
1747
  console.clear();
1491
- console.log(pc8.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
1492
- console.log(pc8.cyan("\u2551 RRCE MCP Hub Running \u2551"));
1493
- console.log(pc8.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
1494
- console.log(pc8.dim("Server is running in Stdio mode (JSON-RPC)."));
1495
- console.log(pc8.dim(`Port: ${newPort} | PID: ${process.pid}`));
1496
- console.log(pc8.dim(`Logging to: ${logPath}`));
1497
- console.log(pc8.dim("---------------------------------------------"));
1498
- };
1499
- const renderFooter = () => {
1500
- console.log(pc8.dim("---------------------------------------------"));
1501
- console.log(pc8.bgBlue(pc8.white(pc8.bold(" COMMANDS "))));
1502
- console.log(`${pc8.bold("q")}: Stop & Quit ${pc8.bold("g")}: Configure Projects ${pc8.bold("p")}: Change Port`);
1748
+ console.log(pc7.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
1749
+ console.log(pc7.cyan("\u2551") + pc7.bold(pc7.white(" RRCE MCP Hub Running ")) + pc7.cyan("\u2551"));
1750
+ console.log(pc7.cyan("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
1751
+ const logLines = logs.slice(-10);
1752
+ const emptyLines = 10 - logLines.length;
1753
+ for (let i = 0; i < emptyLines; i++) {
1754
+ console.log(pc7.cyan("\u2551") + " ".repeat(63) + pc7.cyan("\u2551"));
1755
+ }
1756
+ for (const line of logLines) {
1757
+ const truncated = line.substring(0, 61).padEnd(61);
1758
+ console.log(pc7.cyan("\u2551") + " " + pc7.dim(truncated) + " " + pc7.cyan("\u2551"));
1759
+ }
1760
+ console.log(pc7.cyan("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
1761
+ const infoLine = ` \u{1F4CB} ${exposedLabel} \u2502 Port: ${newPort} \u2502 PID: ${process.pid}`.substring(0, 61).padEnd(61);
1762
+ console.log(pc7.cyan("\u2551") + pc7.yellow(infoLine) + " " + pc7.cyan("\u2551"));
1763
+ console.log(pc7.cyan("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
1764
+ const cmdLine = ` q:Quit p:Projects i:Install r:Reload c:Clear ?:Help`;
1765
+ console.log(pc7.cyan("\u2551") + pc7.dim(cmdLine.padEnd(63)) + pc7.cyan("\u2551"));
1766
+ console.log(pc7.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
1503
1767
  };
1504
- renderHeader();
1505
- renderFooter();
1768
+ let logBuffer = [];
1769
+ render(logBuffer);
1506
1770
  try {
1507
1771
  await startMCPServer();
1508
1772
  let lastSize = 0;
@@ -1517,14 +1781,59 @@ async function handleStartServer() {
1517
1781
  process.stdin.setEncoding("utf8");
1518
1782
  }
1519
1783
  return new Promise((resolve) => {
1784
+ const cleanup = () => {
1785
+ isRunning = false;
1786
+ clearInterval(interval);
1787
+ if (process.stdin.setRawMode) {
1788
+ process.stdin.setRawMode(false);
1789
+ }
1790
+ process.stdin.removeListener("data", onKey);
1791
+ process.stdin.pause();
1792
+ stopMCPServer();
1793
+ console.log("");
1794
+ };
1520
1795
  const onKey = async (key) => {
1521
1796
  if (key === "" || key.toLowerCase() === "q") {
1522
1797
  cleanup();
1523
1798
  resolve();
1799
+ return;
1800
+ }
1801
+ if (key.toLowerCase() === "p") {
1802
+ cleanup();
1803
+ console.clear();
1804
+ await handleConfigure();
1805
+ resolve();
1806
+ return;
1524
1807
  }
1525
- if (key.toLowerCase() === "p" || key.toLowerCase() === "g") {
1808
+ if (key.toLowerCase() === "i") {
1526
1809
  cleanup();
1810
+ console.clear();
1811
+ await handleInstallWizard(workspacePath);
1527
1812
  resolve();
1813
+ return;
1814
+ }
1815
+ if (key.toLowerCase() === "r") {
1816
+ logBuffer.push("[INFO] Reloading configuration...");
1817
+ render(logBuffer);
1818
+ return;
1819
+ }
1820
+ if (key.toLowerCase() === "c") {
1821
+ logBuffer = [];
1822
+ render(logBuffer);
1823
+ return;
1824
+ }
1825
+ if (key === "?") {
1826
+ logBuffer.push("\u2500".repeat(40));
1827
+ logBuffer.push("Commands:");
1828
+ logBuffer.push(" q - Stop server and return to menu");
1829
+ logBuffer.push(" p - Reconfigure exposed projects");
1830
+ logBuffer.push(" i - Install to additional IDEs");
1831
+ logBuffer.push(" r - Reload configuration");
1832
+ logBuffer.push(" c - Clear log display");
1833
+ logBuffer.push(" ? - Show this help");
1834
+ logBuffer.push("\u2500".repeat(40));
1835
+ render(logBuffer);
1836
+ return;
1528
1837
  }
1529
1838
  };
1530
1839
  process.stdin.on("data", onKey);
@@ -1533,35 +1842,27 @@ async function handleStartServer() {
1533
1842
  if (fs16.existsSync(logPath)) {
1534
1843
  const stats = fs16.statSync(logPath);
1535
1844
  if (stats.size > lastSize) {
1536
- const stream = fs16.createReadStream(logPath, {
1537
- start: lastSize,
1538
- end: stats.size,
1539
- encoding: "utf-8"
1540
- });
1541
- stream.on("data", (chunk) => {
1542
- process.stderr.write(chunk);
1543
- });
1845
+ const buffer = Buffer.alloc(stats.size - lastSize);
1846
+ const fd = fs16.openSync(logPath, "r");
1847
+ fs16.readSync(fd, buffer, 0, buffer.length, lastSize);
1848
+ fs16.closeSync(fd);
1849
+ const newContent = buffer.toString("utf-8");
1850
+ const newLines = newContent.split("\n").filter((l) => l.trim());
1851
+ logBuffer.push(...newLines);
1852
+ if (logBuffer.length > 100) {
1853
+ logBuffer = logBuffer.slice(-100);
1854
+ }
1544
1855
  lastSize = stats.size;
1856
+ render(logBuffer);
1545
1857
  }
1546
1858
  }
1547
1859
  }, 500);
1548
- const cleanup = () => {
1549
- isRunning = false;
1550
- clearInterval(interval);
1551
- if (process.stdin.setRawMode) {
1552
- process.stdin.setRawMode(false);
1553
- }
1554
- process.stdin.removeListener("data", onKey);
1555
- process.stdin.pause();
1556
- stopMCPServer();
1557
- console.log("");
1558
- };
1559
1860
  });
1560
1861
  } catch (error) {
1561
1862
  if (process.stdin.setRawMode) {
1562
1863
  process.stdin.setRawMode(false);
1563
1864
  }
1564
- console.error(pc8.red("\nFailed to start server:"));
1865
+ console.error(pc7.red("\nFailed to start server:"));
1565
1866
  console.error(error);
1566
1867
  }
1567
1868
  }
@@ -1569,11 +1870,11 @@ async function handleConfigureGlobalPath() {
1569
1870
  const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
1570
1871
  const fs16 = await import("fs");
1571
1872
  const path16 = await import("path");
1572
- note7(
1573
- `MCP Hub requires a ${pc8.bold("global storage path")} to store its configuration
1873
+ note6(
1874
+ `MCP Hub requires a ${pc7.bold("global storage path")} to store its configuration
1574
1875
  and coordinate across projects.
1575
1876
 
1576
- Your current setup uses ${pc8.cyan("workspace")} mode, which stores data
1877
+ Your current setup uses ${pc7.cyan("workspace")} mode, which stores data
1577
1878
  locally in each project. MCP needs a central location.`,
1578
1879
  "Global Path Required"
1579
1880
  );
@@ -1587,8 +1888,8 @@ locally in each project. MCP needs a central location.`,
1587
1888
  }
1588
1889
  const config = loadMCPConfig();
1589
1890
  saveMCPConfig(config);
1590
- note7(
1591
- `${pc8.green("\u2713")} Global path configured: ${pc8.cyan(resolvedPath)}
1891
+ note6(
1892
+ `${pc7.green("\u2713")} Global path configured: ${pc7.cyan(resolvedPath)}
1592
1893
 
1593
1894
  MCP config will be stored at:
1594
1895
  ${path16.join(resolvedPath, "mcp.yaml")}`,
@@ -1596,54 +1897,63 @@ ${path16.join(resolvedPath, "mcp.yaml")}`,
1596
1897
  );
1597
1898
  return true;
1598
1899
  } catch (error) {
1599
- note7(
1600
- `${pc8.red("\u2717")} Failed to create directory: ${error instanceof Error ? error.message : String(error)}`,
1900
+ note6(
1901
+ `${pc7.red("\u2717")} Failed to create directory: ${error instanceof Error ? error.message : String(error)}`,
1601
1902
  "Error"
1602
1903
  );
1603
1904
  return false;
1604
1905
  }
1605
1906
  }
1606
1907
  async function handleShowStatus() {
1607
- const s = spinner6();
1908
+ const s = spinner5();
1608
1909
  s.start("Loading projects...");
1609
1910
  const config = loadMCPConfig();
1610
1911
  const projects = scanForProjects();
1912
+ const workspacePath = detectWorkspaceRoot();
1913
+ const installStatus = checkInstallStatus(workspacePath);
1611
1914
  s.stop("Projects loaded");
1612
1915
  if (projects.length === 0) {
1613
- note7('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
1916
+ note6('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
1614
1917
  return;
1615
1918
  }
1616
1919
  const lines = [
1617
- `${pc8.bold("Project Status")}`,
1920
+ `${pc7.bold("Installation Status")}`,
1921
+ "",
1922
+ ` Antigravity: ${installStatus.antigravity ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")}`,
1923
+ ` VSCode (Global): ${installStatus.vscodeGlobal ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")}`,
1924
+ ` VSCode (Workspace): ${installStatus.vscodeWorkspace ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")}`,
1925
+ ` Claude Desktop: ${installStatus.claude ? pc7.green("\u2713 Installed") : pc7.dim("Not installed")}`,
1926
+ "",
1927
+ `${pc7.bold("Project Status")}`,
1618
1928
  ""
1619
1929
  ];
1620
1930
  for (const project of projects) {
1621
1931
  const projectConfig = config.projects.find((p) => p.name === project.name);
1622
1932
  const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
1623
- const status = isExposed ? pc8.green("\u2713 exposed") : pc8.dim("\u25CB hidden");
1624
- const source = pc8.dim(`(${project.source})`);
1933
+ const status = isExposed ? pc7.green("\u2713 exposed") : pc7.dim("\u25CB hidden");
1934
+ const source = pc7.dim(`(${project.source})`);
1625
1935
  lines.push(` ${status} ${project.name} ${source}`);
1626
1936
  }
1627
1937
  lines.push("");
1628
- lines.push(pc8.dim(`Config: ${getMCPConfigPath()}`));
1938
+ lines.push(pc7.dim(`Config: ${getMCPConfigPath()}`));
1629
1939
  const serverStatus = getMCPServerStatus();
1630
1940
  if (serverStatus.running) {
1631
- lines.push(pc8.green(`Server: running on port ${serverStatus.port}`));
1941
+ lines.push(pc7.green(`Server: running on port ${serverStatus.port}`));
1632
1942
  } else {
1633
- lines.push(pc8.dim("Server: not running"));
1943
+ lines.push(pc7.dim("Server: not running"));
1634
1944
  }
1635
- note7(lines.join("\n"), "MCP Hub Status");
1945
+ note6(lines.join("\n"), "MCP Hub Status");
1636
1946
  }
1637
1947
  async function handleConfigure() {
1638
1948
  const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
1639
- const s = spinner6();
1949
+ const s = spinner5();
1640
1950
  s.start("Scanning for projects...");
1641
1951
  const config = loadMCPConfig();
1642
1952
  const projects = scanForProjects();
1643
1953
  logger2.info("Configure: Loaded config", { projects: config.projects, defaultMode: config.defaults.includeNew });
1644
1954
  s.stop("Projects found");
1645
1955
  if (projects.length === 0) {
1646
- note7('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
1956
+ note6('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
1647
1957
  return;
1648
1958
  }
1649
1959
  const options = projects.map((project) => {
@@ -1651,7 +1961,7 @@ async function handleConfigure() {
1651
1961
  const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
1652
1962
  return {
1653
1963
  value: project.name,
1654
- label: `${project.name} ${pc8.dim(`(${project.source})`)}`,
1964
+ label: `${project.name} ${pc7.dim(`(${project.source})`)}`,
1655
1965
  hint: project.dataPath
1656
1966
  };
1657
1967
  });
@@ -1665,7 +1975,7 @@ async function handleConfigure() {
1665
1975
  initialValues: currentlyExposed,
1666
1976
  required: false
1667
1977
  });
1668
- if (isCancel7(selected)) {
1978
+ if (isCancel6(selected)) {
1669
1979
  return;
1670
1980
  }
1671
1981
  const selectedNames = selected;
@@ -1677,8 +1987,8 @@ async function handleConfigure() {
1677
1987
  saveMCPConfig(config);
1678
1988
  logger2.info("Configure: Config saved", config);
1679
1989
  const exposedCount = selectedNames.length;
1680
- note7(
1681
- `${pc8.green("\u2713")} Configuration saved!
1990
+ note6(
1991
+ `${pc7.green("\u2713")} Configuration saved!
1682
1992
 
1683
1993
  Exposed projects: ${exposedCount}
1684
1994
  Hidden projects: ${projects.length - exposedCount}`,
@@ -1688,65 +1998,57 @@ Hidden projects: ${projects.length - exposedCount}`,
1688
1998
  async function handleStopServer() {
1689
1999
  const status = getMCPServerStatus();
1690
2000
  if (!status.running) {
1691
- note7("MCP server is not running.", "Status");
2001
+ note6("MCP server is not running.", "Status");
1692
2002
  return;
1693
2003
  }
1694
2004
  const confirmed = await confirm4({
1695
2005
  message: "Stop the MCP server?",
1696
2006
  initialValue: true
1697
2007
  });
1698
- if (isCancel7(confirmed) || !confirmed) {
2008
+ if (isCancel6(confirmed) || !confirmed) {
1699
2009
  return;
1700
2010
  }
1701
2011
  stopMCPServer();
1702
- note7(pc8.green("MCP server stopped."), "Server Stopped");
2012
+ note6(pc7.green("MCP server stopped."), "Server Stopped");
1703
2013
  }
1704
2014
  function showHelp() {
1705
2015
  const help = `
1706
- ${pc8.bold("RRCE MCP Hub")} - Cross-project AI assistant server
2016
+ ${pc7.bold("RRCE MCP Hub")} - Cross-project AI assistant server
1707
2017
 
1708
- ${pc8.bold("ABOUT")}
2018
+ ${pc7.bold("ABOUT")}
1709
2019
  MCP (Model Context Protocol) allows AI assistants like Claude to
1710
2020
  access your project knowledge in real-time. The RRCE MCP Hub
1711
2021
  provides a central server that exposes selected projects.
1712
2022
 
1713
- ${pc8.bold("MENU OPTIONS")}
1714
- ${pc8.cyan("View project status")} See which projects are exposed
1715
- ${pc8.cyan("Configure projects")} Choose which projects to expose
1716
- ${pc8.cyan("Start MCP server")} Start the server for AI access
1717
- ${pc8.cyan("Stop MCP server")} Stop the running server
2023
+ ${pc7.bold("MENU OPTIONS")}
2024
+ ${pc7.cyan("Start MCP server")} Start the server for AI access
2025
+ ${pc7.cyan("Configure projects")} Choose which projects to expose
2026
+ ${pc7.cyan("Install to IDE")} Add to Antigravity, VSCode, or Claude
2027
+ ${pc7.cyan("View status")} See which projects are exposed
1718
2028
 
1719
- ${pc8.bold("DIRECT COMMANDS")}
1720
- ${pc8.dim("rrce-workflow mcp start")} Start server directly
1721
- ${pc8.dim("rrce-workflow mcp stop")} Stop server directly
1722
- ${pc8.dim("rrce-workflow mcp status")} Show status directly
1723
- ${pc8.dim("rrce-workflow mcp help")} Show this help
2029
+ ${pc7.bold("DIRECT COMMANDS")}
2030
+ ${pc7.dim("rrce-workflow mcp start")} Start server directly
2031
+ ${pc7.dim("rrce-workflow mcp stop")} Stop server directly
2032
+ ${pc7.dim("rrce-workflow mcp status")} Show status directly
2033
+ ${pc7.dim("rrce-workflow mcp help")} Show this help
1724
2034
 
1725
- ${pc8.bold("CLAUDE DESKTOP SETUP")}
1726
- Add to ${pc8.cyan("~/.config/claude/claude_desktop_config.json")}:
1727
- ${pc8.dim(`{
1728
- "mcpServers": {
1729
- "rrce": {
1730
- "command": "npx",
1731
- "args": ["rrce-workflow", "mcp", "start"]
1732
- }
1733
- }
1734
- }`)}
2035
+ ${pc7.bold("IDE INSTALLATION")}
2036
+ ${pc7.cyan("Antigravity")} ~/.gemini/antigravity/mcp_config.json
2037
+ ${pc7.cyan("VSCode Global")} ~/.config/Code/User/settings.json
2038
+ ${pc7.cyan("VSCode Workspace")} .vscode/mcp.json
2039
+ ${pc7.cyan("Claude Desktop")} ~/.config/claude/claude_desktop_config.json
1735
2040
 
1736
- ${pc8.bold("RESOURCES EXPOSED")}
1737
- ${pc8.cyan("rrce://projects")} List all exposed projects
1738
- ${pc8.cyan("rrce://projects/{name}/context")} Get project context
1739
- ${pc8.cyan("rrce://projects/{name}/tasks")} Get project tasks
2041
+ ${pc7.bold("SERVER COMMANDS")} (while running)
2042
+ ${pc7.cyan("q")} Stop and quit ${pc7.cyan("p")} Reconfigure projects
2043
+ ${pc7.cyan("i")} Install to IDE ${pc7.cyan("r")} Reload config
2044
+ ${pc7.cyan("c")} Clear logs ${pc7.cyan("?")} Show help
1740
2045
 
1741
- ${pc8.bold("PROMPTS (Agent Commands)")}
1742
- ${pc8.cyan("init")} Initialize project context
1743
- ${pc8.cyan("research")} Research requirements for a task
1744
- ${pc8.cyan("plan")} Create execution plan
1745
- ${pc8.cyan("execute")} Implement planned work
1746
- ${pc8.cyan("docs")} Generate documentation
1747
- ${pc8.cyan("sync")} Sync knowledge with codebase
2046
+ ${pc7.bold("RESOURCES EXPOSED")}
2047
+ ${pc7.cyan("rrce://projects")} List all exposed projects
2048
+ ${pc7.cyan("rrce://projects/{name}/context")} Get project context
2049
+ ${pc7.cyan("rrce://projects/{name}/tasks")} Get project tasks
1748
2050
  `;
1749
- note7(help.trim(), "Help");
2051
+ note6(help.trim(), "Help");
1750
2052
  }
1751
2053
  var init_mcp = __esm({
1752
2054
  "src/mcp/index.ts"() {
@@ -1755,13 +2057,14 @@ var init_mcp = __esm({
1755
2057
  init_detection();
1756
2058
  init_server();
1757
2059
  init_install();
2060
+ init_paths();
1758
2061
  }
1759
2062
  });
1760
2063
 
1761
2064
  // src/commands/wizard/index.ts
1762
- import { intro, select as select3, spinner as spinner5, note as note6, outro as outro5, isCancel as isCancel6 } from "@clack/prompts";
1763
- import pc7 from "picocolors";
1764
- import * as fs11 from "fs";
2065
+ import { intro as intro2, select as select4, spinner as spinner6, note as note7, outro as outro6, isCancel as isCancel7 } from "@clack/prompts";
2066
+ import pc8 from "picocolors";
2067
+ import * as fs15 from "fs";
1765
2068
 
1766
2069
  // src/lib/git.ts
1767
2070
  import { execSync } from "child_process";
@@ -2363,18 +2666,19 @@ function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot,
2363
2666
  }
2364
2667
 
2365
2668
  // src/commands/wizard/index.ts
2669
+ init_mcp();
2366
2670
  async function runWizard() {
2367
- intro(pc7.cyan(pc7.inverse(" RRCE-Workflow Setup ")));
2368
- const s = spinner5();
2671
+ intro2(pc8.cyan(pc8.inverse(" RRCE-Workflow Setup ")));
2672
+ const s = spinner6();
2369
2673
  s.start("Detecting environment");
2370
2674
  const workspacePath = detectWorkspaceRoot();
2371
2675
  const workspaceName = getWorkspaceName(workspacePath);
2372
2676
  const gitUser = getGitUser();
2373
2677
  await new Promise((r) => setTimeout(r, 800));
2374
2678
  s.stop("Environment detected");
2375
- note6(
2376
- `Git User: ${pc7.bold(gitUser || "(not found)")}
2377
- Workspace: ${pc7.bold(workspaceName)}`,
2679
+ note7(
2680
+ `Git User: ${pc8.bold(gitUser || "(not found)")}
2681
+ Workspace: ${pc8.bold(workspaceName)}`,
2378
2682
  "Context"
2379
2683
  );
2380
2684
  const detectedProjects = scanForProjects({
@@ -2382,44 +2686,53 @@ Workspace: ${pc7.bold(workspaceName)}`,
2382
2686
  workspacePath
2383
2687
  });
2384
2688
  const configFilePath = getConfigPath(workspacePath);
2385
- const isAlreadyConfigured = fs11.existsSync(configFilePath);
2689
+ const isAlreadyConfigured = fs15.existsSync(configFilePath);
2386
2690
  let currentStorageMode = null;
2387
2691
  if (isAlreadyConfigured) {
2388
2692
  try {
2389
- const configContent = fs11.readFileSync(configFilePath, "utf-8");
2693
+ const configContent = fs15.readFileSync(configFilePath, "utf-8");
2390
2694
  const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
2391
2695
  currentStorageMode = modeMatch?.[1] ?? null;
2392
2696
  } catch {
2393
2697
  }
2394
2698
  }
2395
2699
  const localDataPath = getLocalWorkspacePath(workspacePath);
2396
- const hasLocalData = fs11.existsSync(localDataPath);
2700
+ const hasLocalData = fs15.existsSync(localDataPath);
2397
2701
  if (isAlreadyConfigured) {
2398
2702
  const menuOptions = [];
2703
+ menuOptions.push({
2704
+ value: "mcp",
2705
+ label: "\u{1F50C} Configure MCP Server",
2706
+ hint: "Expose projects to AI assistants (VSCode, Antigravity, Claude)"
2707
+ });
2399
2708
  if (detectedProjects.length > 0) {
2400
2709
  menuOptions.push({
2401
2710
  value: "link",
2402
- label: "Link other project knowledge",
2711
+ label: "\u{1F517} Link other project knowledge",
2403
2712
  hint: `${detectedProjects.length} projects detected (global + sibling)`
2404
2713
  });
2405
2714
  }
2406
2715
  if (currentStorageMode === "workspace" && hasLocalData) {
2407
2716
  menuOptions.push({
2408
2717
  value: "sync-global",
2409
- label: "Sync to global storage",
2718
+ label: "\u2601\uFE0F Sync to global storage",
2410
2719
  hint: "Share knowledge with other projects"
2411
2720
  });
2412
2721
  }
2413
- menuOptions.push({ value: "update", label: "Update from package", hint: "Get latest prompts & templates" });
2414
- menuOptions.push({ value: "exit", label: "Exit" });
2415
- const action = await select3({
2722
+ menuOptions.push({ value: "update", label: "\u{1F4E6} Update from package", hint: "Get latest prompts & templates" });
2723
+ menuOptions.push({ value: "exit", label: "\u21A9 Exit" });
2724
+ const action = await select4({
2416
2725
  message: "This workspace is already configured. What would you like to do?",
2417
2726
  options: menuOptions
2418
2727
  });
2419
- if (isCancel6(action) || action === "exit") {
2420
- outro5("Exited.");
2728
+ if (isCancel7(action) || action === "exit") {
2729
+ outro6("Exited.");
2421
2730
  process.exit(0);
2422
2731
  }
2732
+ if (action === "mcp") {
2733
+ await runMCP();
2734
+ return;
2735
+ }
2423
2736
  if (action === "link") {
2424
2737
  await runLinkProjectsFlow(workspacePath, workspaceName);
2425
2738
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rrce-workflow",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
5
5
  "author": "RRCE Team",
6
6
  "license": "MIT",