rrce-workflow 0.2.28 → 0.2.30
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 +764 -543
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -8,6 +8,22 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// src/lib/git.ts
|
|
12
|
+
import { execSync } from "child_process";
|
|
13
|
+
function getGitUser() {
|
|
14
|
+
try {
|
|
15
|
+
const result = execSync("git config user.name", { encoding: "utf-8" });
|
|
16
|
+
return result.trim() || null;
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
var init_git = __esm({
|
|
22
|
+
"src/lib/git.ts"() {
|
|
23
|
+
"use strict";
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
11
27
|
// src/lib/paths.ts
|
|
12
28
|
import * as fs from "fs";
|
|
13
29
|
import * as path from "path";
|
|
@@ -366,6 +382,128 @@ var init_prompts = __esm({
|
|
|
366
382
|
}
|
|
367
383
|
});
|
|
368
384
|
|
|
385
|
+
// src/commands/wizard/utils.ts
|
|
386
|
+
import * as fs4 from "fs";
|
|
387
|
+
import * as path4 from "path";
|
|
388
|
+
function copyPromptsToDir(prompts, targetDir, extension) {
|
|
389
|
+
for (const prompt of prompts) {
|
|
390
|
+
const baseName = path4.basename(prompt.filePath, ".md");
|
|
391
|
+
const targetName = baseName + extension;
|
|
392
|
+
const targetPath = path4.join(targetDir, targetName);
|
|
393
|
+
const content = fs4.readFileSync(prompt.filePath, "utf-8");
|
|
394
|
+
fs4.writeFileSync(targetPath, content);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function copyDirRecursive(src, dest) {
|
|
398
|
+
const entries = fs4.readdirSync(src, { withFileTypes: true });
|
|
399
|
+
for (const entry of entries) {
|
|
400
|
+
const srcPath = path4.join(src, entry.name);
|
|
401
|
+
const destPath = path4.join(dest, entry.name);
|
|
402
|
+
if (entry.isDirectory()) {
|
|
403
|
+
ensureDir(destPath);
|
|
404
|
+
copyDirRecursive(srcPath, destPath);
|
|
405
|
+
} else {
|
|
406
|
+
fs4.copyFileSync(srcPath, destPath);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
var init_utils = __esm({
|
|
411
|
+
"src/commands/wizard/utils.ts"() {
|
|
412
|
+
"use strict";
|
|
413
|
+
init_paths();
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// src/commands/wizard/vscode.ts
|
|
418
|
+
import * as fs5 from "fs";
|
|
419
|
+
import * as path5 from "path";
|
|
420
|
+
function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
421
|
+
const workspaceFilePath = path5.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
422
|
+
let workspace;
|
|
423
|
+
if (fs5.existsSync(workspaceFilePath)) {
|
|
424
|
+
try {
|
|
425
|
+
const content = fs5.readFileSync(workspaceFilePath, "utf-8");
|
|
426
|
+
workspace = JSON.parse(content);
|
|
427
|
+
} catch {
|
|
428
|
+
workspace = { folders: [], settings: {} };
|
|
429
|
+
}
|
|
430
|
+
} else {
|
|
431
|
+
workspace = { folders: [], settings: {} };
|
|
432
|
+
}
|
|
433
|
+
if (!workspace.settings) {
|
|
434
|
+
workspace.settings = {};
|
|
435
|
+
}
|
|
436
|
+
workspace.folders = workspace.folders.filter(
|
|
437
|
+
(f) => f.path === "." || !f.name?.startsWith("\u{1F4C1}") && !f.name?.startsWith("\u{1F4DA}") && !f.name?.startsWith("\u{1F4CE}") && !f.name?.startsWith("\u{1F4CB}")
|
|
438
|
+
);
|
|
439
|
+
const mainFolderIndex = workspace.folders.findIndex((f) => f.path === ".");
|
|
440
|
+
if (mainFolderIndex === -1) {
|
|
441
|
+
workspace.folders.unshift({
|
|
442
|
+
path: ".",
|
|
443
|
+
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
444
|
+
});
|
|
445
|
+
} else {
|
|
446
|
+
workspace.folders[mainFolderIndex] = {
|
|
447
|
+
path: ".",
|
|
448
|
+
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
const referenceFolderPaths = [];
|
|
452
|
+
const isDetectedProjects = linkedProjects.length > 0 && typeof linkedProjects[0] === "object";
|
|
453
|
+
if (isDetectedProjects) {
|
|
454
|
+
const projects = linkedProjects;
|
|
455
|
+
for (const project of projects) {
|
|
456
|
+
const sourceLabel = project.source === "global" ? "global" : "local";
|
|
457
|
+
const folderPath = project.dataPath;
|
|
458
|
+
if (fs5.existsSync(folderPath)) {
|
|
459
|
+
referenceFolderPaths.push(folderPath);
|
|
460
|
+
workspace.folders.push({
|
|
461
|
+
path: folderPath,
|
|
462
|
+
name: `\u{1F4C1} ${project.name} [${sourceLabel}]`
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
const projectNames = linkedProjects;
|
|
468
|
+
const rrceHome = customGlobalPath || getRRCEHome();
|
|
469
|
+
for (const projectName of projectNames) {
|
|
470
|
+
const folderPath = path5.join(rrceHome, "workspaces", projectName);
|
|
471
|
+
if (fs5.existsSync(folderPath)) {
|
|
472
|
+
referenceFolderPaths.push(folderPath);
|
|
473
|
+
workspace.folders.push({
|
|
474
|
+
path: folderPath,
|
|
475
|
+
name: `\u{1F4C1} ${projectName} [global]`
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (referenceFolderPaths.length > 0) {
|
|
481
|
+
const readonlyPatterns = {};
|
|
482
|
+
for (const folderPath of referenceFolderPaths) {
|
|
483
|
+
readonlyPatterns[`${folderPath}/**`] = true;
|
|
484
|
+
}
|
|
485
|
+
const existingReadonly = workspace.settings["files.readonlyInclude"] || {};
|
|
486
|
+
const cleanedReadonly = {};
|
|
487
|
+
for (const [pattern, value] of Object.entries(existingReadonly)) {
|
|
488
|
+
if (!pattern.includes(".rrce-workflow") && !pattern.includes("rrce-workflow/workspaces")) {
|
|
489
|
+
cleanedReadonly[pattern] = value;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
workspace.settings["files.readonlyInclude"] = {
|
|
493
|
+
...cleanedReadonly,
|
|
494
|
+
...readonlyPatterns
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
fs5.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
498
|
+
}
|
|
499
|
+
var init_vscode = __esm({
|
|
500
|
+
"src/commands/wizard/vscode.ts"() {
|
|
501
|
+
"use strict";
|
|
502
|
+
init_paths();
|
|
503
|
+
init_detection();
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
|
|
369
507
|
// src/lib/autocomplete-prompt.ts
|
|
370
508
|
import * as fs6 from "fs";
|
|
371
509
|
import * as path6 from "path";
|
|
@@ -583,20 +721,31 @@ var init_types = __esm({
|
|
|
583
721
|
});
|
|
584
722
|
|
|
585
723
|
// src/mcp/config.ts
|
|
586
|
-
|
|
587
|
-
|
|
724
|
+
var config_exports = {};
|
|
725
|
+
__export(config_exports, {
|
|
726
|
+
ensureMCPGlobalPath: () => ensureMCPGlobalPath,
|
|
727
|
+
getMCPConfigPath: () => getMCPConfigPath,
|
|
728
|
+
getProjectPermissions: () => getProjectPermissions,
|
|
729
|
+
isProjectExposed: () => isProjectExposed,
|
|
730
|
+
loadMCPConfig: () => loadMCPConfig,
|
|
731
|
+
removeProjectConfig: () => removeProjectConfig,
|
|
732
|
+
saveMCPConfig: () => saveMCPConfig,
|
|
733
|
+
setProjectConfig: () => setProjectConfig
|
|
734
|
+
});
|
|
735
|
+
import * as fs7 from "fs";
|
|
736
|
+
import * as path8 from "path";
|
|
588
737
|
function getMCPConfigPath() {
|
|
589
738
|
const workspaceRoot = detectWorkspaceRoot();
|
|
590
739
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
591
|
-
return
|
|
740
|
+
return path8.join(rrceHome, "mcp.yaml");
|
|
592
741
|
}
|
|
593
742
|
function ensureMCPGlobalPath() {
|
|
594
743
|
const workspaceRoot = detectWorkspaceRoot();
|
|
595
744
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
596
745
|
if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
|
|
597
|
-
const configPath =
|
|
598
|
-
if (
|
|
599
|
-
const content =
|
|
746
|
+
const configPath = path8.join(workspaceRoot, ".rrce-workflow", "config.yaml");
|
|
747
|
+
if (fs7.existsSync(configPath)) {
|
|
748
|
+
const content = fs7.readFileSync(configPath, "utf-8");
|
|
600
749
|
const modeMatch = content.match(/mode:\s*(global|workspace)/);
|
|
601
750
|
if (modeMatch?.[1] === "workspace") {
|
|
602
751
|
return {
|
|
@@ -614,11 +763,11 @@ function ensureMCPGlobalPath() {
|
|
|
614
763
|
}
|
|
615
764
|
function loadMCPConfig() {
|
|
616
765
|
const configPath = getMCPConfigPath();
|
|
617
|
-
if (!
|
|
766
|
+
if (!fs7.existsSync(configPath)) {
|
|
618
767
|
return { ...DEFAULT_MCP_CONFIG };
|
|
619
768
|
}
|
|
620
769
|
try {
|
|
621
|
-
const content =
|
|
770
|
+
const content = fs7.readFileSync(configPath, "utf-8");
|
|
622
771
|
return parseMCPConfig(content);
|
|
623
772
|
} catch {
|
|
624
773
|
return { ...DEFAULT_MCP_CONFIG };
|
|
@@ -626,12 +775,12 @@ function loadMCPConfig() {
|
|
|
626
775
|
}
|
|
627
776
|
function saveMCPConfig(config) {
|
|
628
777
|
const configPath = getMCPConfigPath();
|
|
629
|
-
const dir =
|
|
630
|
-
if (!
|
|
631
|
-
|
|
778
|
+
const dir = path8.dirname(configPath);
|
|
779
|
+
if (!fs7.existsSync(dir)) {
|
|
780
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
632
781
|
}
|
|
633
782
|
const content = serializeMCPConfig(config);
|
|
634
|
-
|
|
783
|
+
fs7.writeFileSync(configPath, content);
|
|
635
784
|
}
|
|
636
785
|
function parseMCPConfig(content) {
|
|
637
786
|
const config = { ...DEFAULT_MCP_CONFIG, projects: [] };
|
|
@@ -769,6 +918,10 @@ function setProjectConfig(config, name, expose, permissions) {
|
|
|
769
918
|
}
|
|
770
919
|
return config;
|
|
771
920
|
}
|
|
921
|
+
function removeProjectConfig(config, name) {
|
|
922
|
+
config.projects = config.projects.filter((p) => p.name !== name);
|
|
923
|
+
return config;
|
|
924
|
+
}
|
|
772
925
|
function isProjectExposed(config, name) {
|
|
773
926
|
const project = config.projects.find((p) => p.name === name);
|
|
774
927
|
if (project) {
|
|
@@ -794,12 +947,12 @@ __export(logger_exports, {
|
|
|
794
947
|
getLogFilePath: () => getLogFilePath,
|
|
795
948
|
logger: () => logger
|
|
796
949
|
});
|
|
797
|
-
import * as
|
|
798
|
-
import * as
|
|
950
|
+
import * as fs8 from "fs";
|
|
951
|
+
import * as path9 from "path";
|
|
799
952
|
function getLogFilePath() {
|
|
800
953
|
const workspaceRoot = detectWorkspaceRoot();
|
|
801
954
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
802
|
-
return
|
|
955
|
+
return path9.join(rrceHome, "mcp-server.log");
|
|
803
956
|
}
|
|
804
957
|
var Logger, logger;
|
|
805
958
|
var init_logger = __esm({
|
|
@@ -830,11 +983,11 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
830
983
|
}
|
|
831
984
|
logMessage += "\n";
|
|
832
985
|
try {
|
|
833
|
-
const dir =
|
|
834
|
-
if (!
|
|
835
|
-
|
|
986
|
+
const dir = path9.dirname(this.logPath);
|
|
987
|
+
if (!fs8.existsSync(dir)) {
|
|
988
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
836
989
|
}
|
|
837
|
-
|
|
990
|
+
fs8.appendFileSync(this.logPath, logMessage);
|
|
838
991
|
} catch (e) {
|
|
839
992
|
console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
|
|
840
993
|
console.error(logMessage);
|
|
@@ -858,8 +1011,8 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
858
1011
|
});
|
|
859
1012
|
|
|
860
1013
|
// src/mcp/resources.ts
|
|
861
|
-
import * as
|
|
862
|
-
import * as
|
|
1014
|
+
import * as fs9 from "fs";
|
|
1015
|
+
import * as path10 from "path";
|
|
863
1016
|
function getExposedProjects() {
|
|
864
1017
|
const config = loadMCPConfig();
|
|
865
1018
|
const allProjects = scanForProjects();
|
|
@@ -886,11 +1039,11 @@ function getProjectContext(projectName) {
|
|
|
886
1039
|
if (!project?.knowledgePath) {
|
|
887
1040
|
return null;
|
|
888
1041
|
}
|
|
889
|
-
const contextPath =
|
|
890
|
-
if (!
|
|
1042
|
+
const contextPath = path10.join(project.knowledgePath, "project-context.md");
|
|
1043
|
+
if (!fs9.existsSync(contextPath)) {
|
|
891
1044
|
return null;
|
|
892
1045
|
}
|
|
893
|
-
return
|
|
1046
|
+
return fs9.readFileSync(contextPath, "utf-8");
|
|
894
1047
|
}
|
|
895
1048
|
function getProjectTasks(projectName) {
|
|
896
1049
|
const config = loadMCPConfig();
|
|
@@ -903,18 +1056,18 @@ function getProjectTasks(projectName) {
|
|
|
903
1056
|
}
|
|
904
1057
|
const projects = scanForProjects();
|
|
905
1058
|
const project = projects.find((p) => p.name === projectName);
|
|
906
|
-
if (!project?.tasksPath || !
|
|
1059
|
+
if (!project?.tasksPath || !fs9.existsSync(project.tasksPath)) {
|
|
907
1060
|
return [];
|
|
908
1061
|
}
|
|
909
1062
|
const tasks = [];
|
|
910
1063
|
try {
|
|
911
|
-
const taskDirs =
|
|
1064
|
+
const taskDirs = fs9.readdirSync(project.tasksPath, { withFileTypes: true });
|
|
912
1065
|
for (const dir of taskDirs) {
|
|
913
1066
|
if (!dir.isDirectory()) continue;
|
|
914
|
-
const metaPath =
|
|
915
|
-
if (
|
|
1067
|
+
const metaPath = path10.join(project.tasksPath, dir.name, "meta.json");
|
|
1068
|
+
if (fs9.existsSync(metaPath)) {
|
|
916
1069
|
try {
|
|
917
|
-
const meta = JSON.parse(
|
|
1070
|
+
const meta = JSON.parse(fs9.readFileSync(metaPath, "utf-8"));
|
|
918
1071
|
tasks.push(meta);
|
|
919
1072
|
} catch {
|
|
920
1073
|
}
|
|
@@ -933,11 +1086,11 @@ function searchKnowledge(query) {
|
|
|
933
1086
|
const permissions = getProjectPermissions(config, project.name);
|
|
934
1087
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
935
1088
|
try {
|
|
936
|
-
const files =
|
|
1089
|
+
const files = fs9.readdirSync(project.knowledgePath);
|
|
937
1090
|
for (const file of files) {
|
|
938
1091
|
if (!file.endsWith(".md")) continue;
|
|
939
|
-
const filePath =
|
|
940
|
-
const content =
|
|
1092
|
+
const filePath = path10.join(project.knowledgePath, file);
|
|
1093
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
941
1094
|
const lines = content.split("\n");
|
|
942
1095
|
const matches = [];
|
|
943
1096
|
for (const line of lines) {
|
|
@@ -1105,8 +1258,9 @@ function registerResourceHandlers(server) {
|
|
|
1105
1258
|
};
|
|
1106
1259
|
}
|
|
1107
1260
|
const projectMatch = uri.match(/^rrce:\/\/projects\/([^/]+)\/(.+)$/);
|
|
1108
|
-
if (projectMatch) {
|
|
1109
|
-
const
|
|
1261
|
+
if (projectMatch && projectMatch[1] && projectMatch[2]) {
|
|
1262
|
+
const projectName = projectMatch[1];
|
|
1263
|
+
const resourceType = projectMatch[2];
|
|
1110
1264
|
const content = resourceType === "context" ? getProjectContext(projectName) : JSON.stringify(getProjectTasks(projectName), null, 2);
|
|
1111
1265
|
if (content === null) throw new Error(`Resource not found: ${uri}`);
|
|
1112
1266
|
return {
|
|
@@ -1357,8 +1511,8 @@ var init_server = __esm({
|
|
|
1357
1511
|
});
|
|
1358
1512
|
|
|
1359
1513
|
// src/mcp/install.ts
|
|
1360
|
-
import * as
|
|
1361
|
-
import * as
|
|
1514
|
+
import * as fs10 from "fs";
|
|
1515
|
+
import * as path11 from "path";
|
|
1362
1516
|
import * as os from "os";
|
|
1363
1517
|
function checkInstallStatus(workspacePath) {
|
|
1364
1518
|
return {
|
|
@@ -1369,37 +1523,37 @@ function checkInstallStatus(workspacePath) {
|
|
|
1369
1523
|
};
|
|
1370
1524
|
}
|
|
1371
1525
|
function checkAntigravityConfig() {
|
|
1372
|
-
if (!
|
|
1526
|
+
if (!fs10.existsSync(ANTIGRAVITY_CONFIG)) return false;
|
|
1373
1527
|
try {
|
|
1374
|
-
const content = JSON.parse(
|
|
1528
|
+
const content = JSON.parse(fs10.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
1375
1529
|
return !!content.mcpServers?.["rrce"];
|
|
1376
1530
|
} catch {
|
|
1377
1531
|
return false;
|
|
1378
1532
|
}
|
|
1379
1533
|
}
|
|
1380
1534
|
function checkClaudeConfig() {
|
|
1381
|
-
if (!
|
|
1535
|
+
if (!fs10.existsSync(CLAUDE_CONFIG)) return false;
|
|
1382
1536
|
try {
|
|
1383
|
-
const content = JSON.parse(
|
|
1537
|
+
const content = JSON.parse(fs10.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
1384
1538
|
return !!content.mcpServers?.["rrce"];
|
|
1385
1539
|
} catch {
|
|
1386
1540
|
return false;
|
|
1387
1541
|
}
|
|
1388
1542
|
}
|
|
1389
1543
|
function checkVSCodeGlobalConfig() {
|
|
1390
|
-
if (!
|
|
1544
|
+
if (!fs10.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
|
|
1391
1545
|
try {
|
|
1392
|
-
const content = JSON.parse(
|
|
1546
|
+
const content = JSON.parse(fs10.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
1393
1547
|
return !!content["mcp.servers"]?.["rrce"];
|
|
1394
1548
|
} catch {
|
|
1395
1549
|
return false;
|
|
1396
1550
|
}
|
|
1397
1551
|
}
|
|
1398
1552
|
function checkVSCodeWorkspaceConfig(workspacePath) {
|
|
1399
|
-
const configPath =
|
|
1400
|
-
if (!
|
|
1553
|
+
const configPath = path11.join(workspacePath, ".vscode", "mcp.json");
|
|
1554
|
+
if (!fs10.existsSync(configPath)) return false;
|
|
1401
1555
|
try {
|
|
1402
|
-
const content = JSON.parse(
|
|
1556
|
+
const content = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
|
|
1403
1557
|
return !!content.servers?.["rrce"];
|
|
1404
1558
|
} catch {
|
|
1405
1559
|
return false;
|
|
@@ -1424,14 +1578,14 @@ function installToConfig(target, workspacePath) {
|
|
|
1424
1578
|
}
|
|
1425
1579
|
}
|
|
1426
1580
|
function installToAntigravity() {
|
|
1427
|
-
const dir =
|
|
1428
|
-
if (!
|
|
1429
|
-
|
|
1581
|
+
const dir = path11.dirname(ANTIGRAVITY_CONFIG);
|
|
1582
|
+
if (!fs10.existsSync(dir)) {
|
|
1583
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1430
1584
|
}
|
|
1431
1585
|
let config = { mcpServers: {} };
|
|
1432
|
-
if (
|
|
1586
|
+
if (fs10.existsSync(ANTIGRAVITY_CONFIG)) {
|
|
1433
1587
|
try {
|
|
1434
|
-
config = JSON.parse(
|
|
1588
|
+
config = JSON.parse(fs10.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
1435
1589
|
} catch {
|
|
1436
1590
|
}
|
|
1437
1591
|
}
|
|
@@ -1441,21 +1595,21 @@ function installToAntigravity() {
|
|
|
1441
1595
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1442
1596
|
};
|
|
1443
1597
|
try {
|
|
1444
|
-
|
|
1598
|
+
fs10.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
|
|
1445
1599
|
return true;
|
|
1446
1600
|
} catch {
|
|
1447
1601
|
return false;
|
|
1448
1602
|
}
|
|
1449
1603
|
}
|
|
1450
1604
|
function installToClaude() {
|
|
1451
|
-
const dir =
|
|
1452
|
-
if (!
|
|
1453
|
-
|
|
1605
|
+
const dir = path11.dirname(CLAUDE_CONFIG);
|
|
1606
|
+
if (!fs10.existsSync(dir)) {
|
|
1607
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1454
1608
|
}
|
|
1455
1609
|
let config = { mcpServers: {} };
|
|
1456
|
-
if (
|
|
1610
|
+
if (fs10.existsSync(CLAUDE_CONFIG)) {
|
|
1457
1611
|
try {
|
|
1458
|
-
config = JSON.parse(
|
|
1612
|
+
config = JSON.parse(fs10.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
1459
1613
|
} catch {
|
|
1460
1614
|
}
|
|
1461
1615
|
}
|
|
@@ -1465,21 +1619,21 @@ function installToClaude() {
|
|
|
1465
1619
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1466
1620
|
};
|
|
1467
1621
|
try {
|
|
1468
|
-
|
|
1622
|
+
fs10.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
|
|
1469
1623
|
return true;
|
|
1470
1624
|
} catch {
|
|
1471
1625
|
return false;
|
|
1472
1626
|
}
|
|
1473
1627
|
}
|
|
1474
1628
|
function installToVSCodeGlobal() {
|
|
1475
|
-
const dir =
|
|
1476
|
-
if (!
|
|
1477
|
-
|
|
1629
|
+
const dir = path11.dirname(VSCODE_GLOBAL_CONFIG);
|
|
1630
|
+
if (!fs10.existsSync(dir)) {
|
|
1631
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1478
1632
|
}
|
|
1479
1633
|
let settings = {};
|
|
1480
|
-
if (
|
|
1634
|
+
if (fs10.existsSync(VSCODE_GLOBAL_CONFIG)) {
|
|
1481
1635
|
try {
|
|
1482
|
-
settings = JSON.parse(
|
|
1636
|
+
settings = JSON.parse(fs10.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
1483
1637
|
} catch {
|
|
1484
1638
|
}
|
|
1485
1639
|
}
|
|
@@ -1489,22 +1643,22 @@ function installToVSCodeGlobal() {
|
|
|
1489
1643
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1490
1644
|
};
|
|
1491
1645
|
try {
|
|
1492
|
-
|
|
1646
|
+
fs10.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
|
|
1493
1647
|
return true;
|
|
1494
1648
|
} catch {
|
|
1495
1649
|
return false;
|
|
1496
1650
|
}
|
|
1497
1651
|
}
|
|
1498
1652
|
function installToVSCodeWorkspace(workspacePath) {
|
|
1499
|
-
const vscodeDir =
|
|
1500
|
-
const configPath =
|
|
1501
|
-
if (!
|
|
1502
|
-
|
|
1653
|
+
const vscodeDir = path11.join(workspacePath, ".vscode");
|
|
1654
|
+
const configPath = path11.join(vscodeDir, "mcp.json");
|
|
1655
|
+
if (!fs10.existsSync(vscodeDir)) {
|
|
1656
|
+
fs10.mkdirSync(vscodeDir, { recursive: true });
|
|
1503
1657
|
}
|
|
1504
1658
|
let config = { servers: {} };
|
|
1505
|
-
if (
|
|
1659
|
+
if (fs10.existsSync(configPath)) {
|
|
1506
1660
|
try {
|
|
1507
|
-
config = JSON.parse(
|
|
1661
|
+
config = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
|
|
1508
1662
|
} catch {
|
|
1509
1663
|
}
|
|
1510
1664
|
}
|
|
@@ -1514,7 +1668,7 @@ function installToVSCodeWorkspace(workspacePath) {
|
|
|
1514
1668
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1515
1669
|
};
|
|
1516
1670
|
try {
|
|
1517
|
-
|
|
1671
|
+
fs10.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1518
1672
|
return true;
|
|
1519
1673
|
} catch {
|
|
1520
1674
|
return false;
|
|
@@ -1538,9 +1692,229 @@ var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG;
|
|
|
1538
1692
|
var init_install = __esm({
|
|
1539
1693
|
"src/mcp/install.ts"() {
|
|
1540
1694
|
"use strict";
|
|
1541
|
-
ANTIGRAVITY_CONFIG =
|
|
1542
|
-
CLAUDE_CONFIG =
|
|
1543
|
-
VSCODE_GLOBAL_CONFIG =
|
|
1695
|
+
ANTIGRAVITY_CONFIG = path11.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
|
|
1696
|
+
CLAUDE_CONFIG = path11.join(os.homedir(), ".config/claude/claude_desktop_config.json");
|
|
1697
|
+
VSCODE_GLOBAL_CONFIG = path11.join(os.homedir(), ".config/Code/User/settings.json");
|
|
1698
|
+
}
|
|
1699
|
+
});
|
|
1700
|
+
|
|
1701
|
+
// src/mcp/ui/Header.tsx
|
|
1702
|
+
import "react";
|
|
1703
|
+
import { Box, Text } from "ink";
|
|
1704
|
+
import { jsx } from "react/jsx-runtime";
|
|
1705
|
+
var Header;
|
|
1706
|
+
var init_Header = __esm({
|
|
1707
|
+
"src/mcp/ui/Header.tsx"() {
|
|
1708
|
+
"use strict";
|
|
1709
|
+
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 " }) }) });
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1713
|
+
// src/mcp/ui/StatusBoard.tsx
|
|
1714
|
+
import "react";
|
|
1715
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
1716
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
1717
|
+
var StatusBoard;
|
|
1718
|
+
var init_StatusBoard = __esm({
|
|
1719
|
+
"src/mcp/ui/StatusBoard.tsx"() {
|
|
1720
|
+
"use strict";
|
|
1721
|
+
StatusBoard = ({ exposedLabel, port, pid }) => {
|
|
1722
|
+
return /* @__PURE__ */ jsx2(Box2, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { children: [
|
|
1723
|
+
"\u{1F4CB} ",
|
|
1724
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: exposedLabel }),
|
|
1725
|
+
" ",
|
|
1726
|
+
"\u2502",
|
|
1727
|
+
" Port: ",
|
|
1728
|
+
/* @__PURE__ */ jsx2(Text2, { color: "green", children: port }),
|
|
1729
|
+
" ",
|
|
1730
|
+
"\u2502",
|
|
1731
|
+
" PID: ",
|
|
1732
|
+
/* @__PURE__ */ jsx2(Text2, { color: "green", children: pid })
|
|
1733
|
+
] }) });
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
});
|
|
1737
|
+
|
|
1738
|
+
// src/mcp/ui/LogViewer.tsx
|
|
1739
|
+
import "react";
|
|
1740
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
1741
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1742
|
+
var LogViewer;
|
|
1743
|
+
var init_LogViewer = __esm({
|
|
1744
|
+
"src/mcp/ui/LogViewer.tsx"() {
|
|
1745
|
+
"use strict";
|
|
1746
|
+
LogViewer = ({ logs, height }) => {
|
|
1747
|
+
const visibleLogs = logs.slice(-height);
|
|
1748
|
+
const emptyLines = Math.max(0, height - visibleLogs.length);
|
|
1749
|
+
const padding = Array(emptyLines).fill("");
|
|
1750
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "dim", paddingX: 1, height: height + 2, flexGrow: 1, children: [
|
|
1751
|
+
padding.map((_, i) => /* @__PURE__ */ jsx3(Text3, { children: " " }, `empty-${i}`)),
|
|
1752
|
+
visibleLogs.map((log, i) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate-end", children: log }, `log-${i}`))
|
|
1753
|
+
] });
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
});
|
|
1757
|
+
|
|
1758
|
+
// src/mcp/ui/CommandBar.tsx
|
|
1759
|
+
import "react";
|
|
1760
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
1761
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1762
|
+
var CommandBar;
|
|
1763
|
+
var init_CommandBar = __esm({
|
|
1764
|
+
"src/mcp/ui/CommandBar.tsx"() {
|
|
1765
|
+
"use strict";
|
|
1766
|
+
CommandBar = () => {
|
|
1767
|
+
return /* @__PURE__ */ jsx4(Box4, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
1768
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "q" }),
|
|
1769
|
+
":Quit ",
|
|
1770
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "p" }),
|
|
1771
|
+
":Projects ",
|
|
1772
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "i" }),
|
|
1773
|
+
":Install ",
|
|
1774
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "r" }),
|
|
1775
|
+
":Reload ",
|
|
1776
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "c" }),
|
|
1777
|
+
":Clear ",
|
|
1778
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "?" }),
|
|
1779
|
+
":Help"
|
|
1780
|
+
] }) });
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
// src/mcp/ui/Dashboard.tsx
|
|
1786
|
+
import "react";
|
|
1787
|
+
import { Box as Box5 } from "ink";
|
|
1788
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1789
|
+
var Dashboard;
|
|
1790
|
+
var init_Dashboard = __esm({
|
|
1791
|
+
"src/mcp/ui/Dashboard.tsx"() {
|
|
1792
|
+
"use strict";
|
|
1793
|
+
init_Header();
|
|
1794
|
+
init_StatusBoard();
|
|
1795
|
+
init_LogViewer();
|
|
1796
|
+
init_CommandBar();
|
|
1797
|
+
Dashboard = ({ logs, exposedLabel, port, pid, logHeight }) => {
|
|
1798
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", padding: 0, children: [
|
|
1799
|
+
/* @__PURE__ */ jsx5(Header, {}),
|
|
1800
|
+
/* @__PURE__ */ jsx5(LogViewer, { logs, height: logHeight }),
|
|
1801
|
+
/* @__PURE__ */ jsx5(StatusBoard, { exposedLabel, port, pid }),
|
|
1802
|
+
/* @__PURE__ */ jsx5(CommandBar, {})
|
|
1803
|
+
] });
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
// src/mcp/ui/App.tsx
|
|
1809
|
+
var App_exports = {};
|
|
1810
|
+
__export(App_exports, {
|
|
1811
|
+
App: () => App
|
|
1812
|
+
});
|
|
1813
|
+
import { useState, useEffect as useEffect2 } from "react";
|
|
1814
|
+
import { useInput, useApp } from "ink";
|
|
1815
|
+
import fs11 from "fs";
|
|
1816
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1817
|
+
var App;
|
|
1818
|
+
var init_App = __esm({
|
|
1819
|
+
"src/mcp/ui/App.tsx"() {
|
|
1820
|
+
"use strict";
|
|
1821
|
+
init_Dashboard();
|
|
1822
|
+
init_config();
|
|
1823
|
+
init_detection();
|
|
1824
|
+
init_logger();
|
|
1825
|
+
init_server();
|
|
1826
|
+
App = ({ onExit, onConfigure, onInstall, initialPort }) => {
|
|
1827
|
+
const { exit } = useApp();
|
|
1828
|
+
const [logs, setLogs] = useState([]);
|
|
1829
|
+
const [serverInfo, setServerInfo] = useState({
|
|
1830
|
+
port: initialPort,
|
|
1831
|
+
pid: process.pid,
|
|
1832
|
+
running: false
|
|
1833
|
+
});
|
|
1834
|
+
const config = loadMCPConfig();
|
|
1835
|
+
const projects = scanForProjects();
|
|
1836
|
+
const exposedProjects = projects.filter((p) => {
|
|
1837
|
+
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1838
|
+
return cfg?.expose ?? config.defaults.includeNew;
|
|
1839
|
+
});
|
|
1840
|
+
const exposedNames = exposedProjects.map((p) => p.name).slice(0, 5);
|
|
1841
|
+
const exposedLabel = exposedNames.length > 0 ? exposedNames.join(", ") + (exposedProjects.length > 5 ? ` (+${exposedProjects.length - 5} more)` : "") : "(none)";
|
|
1842
|
+
useEffect2(() => {
|
|
1843
|
+
const start = async () => {
|
|
1844
|
+
const status = getMCPServerStatus();
|
|
1845
|
+
if (!status.running) {
|
|
1846
|
+
try {
|
|
1847
|
+
const res = await startMCPServer();
|
|
1848
|
+
setServerInfo((prev) => ({ ...prev, running: true, port: res.port, pid: res.pid }));
|
|
1849
|
+
} catch (e) {
|
|
1850
|
+
setLogs((prev) => [...prev, `Error starting server: ${e}`]);
|
|
1851
|
+
}
|
|
1852
|
+
} else {
|
|
1853
|
+
setServerInfo((prev) => ({ ...prev, running: true, port: status.port || initialPort, pid: status.pid || process.pid }));
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
start();
|
|
1857
|
+
return () => {
|
|
1858
|
+
};
|
|
1859
|
+
}, []);
|
|
1860
|
+
useEffect2(() => {
|
|
1861
|
+
const logPath = getLogFilePath();
|
|
1862
|
+
let lastSize = 0;
|
|
1863
|
+
if (fs11.existsSync(logPath)) {
|
|
1864
|
+
const stats = fs11.statSync(logPath);
|
|
1865
|
+
lastSize = stats.size;
|
|
1866
|
+
}
|
|
1867
|
+
const interval = setInterval(() => {
|
|
1868
|
+
if (fs11.existsSync(logPath)) {
|
|
1869
|
+
const stats = fs11.statSync(logPath);
|
|
1870
|
+
if (stats.size > lastSize) {
|
|
1871
|
+
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
1872
|
+
const fd = fs11.openSync(logPath, "r");
|
|
1873
|
+
fs11.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
1874
|
+
fs11.closeSync(fd);
|
|
1875
|
+
const newContent = buffer.toString("utf-8");
|
|
1876
|
+
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
1877
|
+
setLogs((prev) => {
|
|
1878
|
+
const next = [...prev, ...newLines];
|
|
1879
|
+
return next.slice(-50);
|
|
1880
|
+
});
|
|
1881
|
+
lastSize = stats.size;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
}, 500);
|
|
1885
|
+
return () => clearInterval(interval);
|
|
1886
|
+
}, []);
|
|
1887
|
+
useInput((input, key) => {
|
|
1888
|
+
if (input === "q" || key.ctrl && input === "c") {
|
|
1889
|
+
stopMCPServer();
|
|
1890
|
+
onExit();
|
|
1891
|
+
}
|
|
1892
|
+
if (input === "p") {
|
|
1893
|
+
onConfigure();
|
|
1894
|
+
}
|
|
1895
|
+
if (input === "i") {
|
|
1896
|
+
onInstall();
|
|
1897
|
+
}
|
|
1898
|
+
if (input === "c") {
|
|
1899
|
+
setLogs([]);
|
|
1900
|
+
}
|
|
1901
|
+
if (input === "r") {
|
|
1902
|
+
setLogs((prev) => [...prev, "[INFO] Config reload requested..."]);
|
|
1903
|
+
}
|
|
1904
|
+
});
|
|
1905
|
+
const termHeight = process.stdout.rows || 24;
|
|
1906
|
+
const logHeight = Math.max(5, termHeight - 12);
|
|
1907
|
+
return /* @__PURE__ */ jsx6(
|
|
1908
|
+
Dashboard,
|
|
1909
|
+
{
|
|
1910
|
+
logs,
|
|
1911
|
+
exposedLabel,
|
|
1912
|
+
port: serverInfo.port,
|
|
1913
|
+
pid: serverInfo.pid,
|
|
1914
|
+
logHeight
|
|
1915
|
+
}
|
|
1916
|
+
);
|
|
1917
|
+
};
|
|
1544
1918
|
}
|
|
1545
1919
|
});
|
|
1546
1920
|
|
|
@@ -1549,15 +1923,19 @@ var mcp_exports = {};
|
|
|
1549
1923
|
__export(mcp_exports, {
|
|
1550
1924
|
runMCP: () => runMCP
|
|
1551
1925
|
});
|
|
1552
|
-
import { intro, outro
|
|
1553
|
-
import
|
|
1926
|
+
import { intro, outro, select as select2, multiselect, confirm, spinner, note as note2, cancel, isCancel as isCancel2, text } from "@clack/prompts";
|
|
1927
|
+
import pc3 from "picocolors";
|
|
1554
1928
|
async function runMCP(subcommand2) {
|
|
1555
1929
|
if (subcommand2) {
|
|
1556
1930
|
switch (subcommand2) {
|
|
1557
1931
|
case "start":
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
}
|
|
1932
|
+
if (process.stdout.isTTY) {
|
|
1933
|
+
await handleStartServer();
|
|
1934
|
+
} else {
|
|
1935
|
+
await startMCPServer();
|
|
1936
|
+
await new Promise(() => {
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1561
1939
|
return;
|
|
1562
1940
|
case "stop":
|
|
1563
1941
|
await handleStopServer();
|
|
@@ -1570,57 +1948,60 @@ async function runMCP(subcommand2) {
|
|
|
1570
1948
|
return;
|
|
1571
1949
|
}
|
|
1572
1950
|
}
|
|
1573
|
-
intro(
|
|
1951
|
+
intro(pc3.bgCyan(pc3.black(" RRCE MCP Hub ")));
|
|
1574
1952
|
const workspacePath = detectWorkspaceRoot();
|
|
1575
1953
|
const globalPathCheck = await ensureMCPGlobalPath();
|
|
1576
1954
|
if (!globalPathCheck.configured) {
|
|
1577
1955
|
const configured = await handleConfigureGlobalPath();
|
|
1578
1956
|
if (!configured) {
|
|
1579
|
-
|
|
1957
|
+
outro(pc3.yellow("MCP requires a global storage path. Setup cancelled."));
|
|
1580
1958
|
return;
|
|
1581
1959
|
}
|
|
1582
1960
|
}
|
|
1583
|
-
const status = checkInstallStatus(workspacePath);
|
|
1584
1961
|
const installed = isInstalledAnywhere(workspacePath);
|
|
1585
1962
|
if (!installed) {
|
|
1586
|
-
|
|
1587
|
-
`${
|
|
1963
|
+
note2(
|
|
1964
|
+
`${pc3.bold("Welcome to RRCE MCP Hub!")}
|
|
1588
1965
|
|
|
1589
1966
|
MCP (Model Context Protocol) allows AI assistants to access your
|
|
1590
1967
|
project knowledge in real-time. Let's get you set up.`,
|
|
1591
1968
|
"Getting Started"
|
|
1592
1969
|
);
|
|
1593
|
-
const shouldInstall = await
|
|
1970
|
+
const shouldInstall = await confirm({
|
|
1594
1971
|
message: "Install MCP server to your IDE(s)?",
|
|
1595
1972
|
initialValue: true
|
|
1596
1973
|
});
|
|
1597
|
-
if (shouldInstall && !
|
|
1974
|
+
if (shouldInstall && !isCancel2(shouldInstall)) {
|
|
1598
1975
|
await handleInstallWizard(workspacePath);
|
|
1599
|
-
|
|
1600
|
-
const
|
|
1976
|
+
const config2 = loadMCPConfig();
|
|
1977
|
+
const exposedCount2 = config2.projects.filter((p) => p.expose).length;
|
|
1978
|
+
if (exposedCount2 === 0) {
|
|
1979
|
+
await handleConfigure();
|
|
1980
|
+
}
|
|
1981
|
+
const shouldStart = await confirm({
|
|
1601
1982
|
message: "Start the MCP server now?",
|
|
1602
1983
|
initialValue: true
|
|
1603
1984
|
});
|
|
1604
|
-
if (shouldStart && !
|
|
1985
|
+
if (shouldStart && !isCancel2(shouldStart)) {
|
|
1605
1986
|
await handleStartServer();
|
|
1606
1987
|
}
|
|
1607
1988
|
}
|
|
1608
|
-
|
|
1989
|
+
outro(pc3.green("MCP Hub setup complete!"));
|
|
1609
1990
|
return;
|
|
1610
1991
|
}
|
|
1611
1992
|
const config = loadMCPConfig();
|
|
1612
1993
|
const exposedCount = config.projects.filter((p) => p.expose).length;
|
|
1613
1994
|
if (exposedCount === 0 && !config.defaults.includeNew) {
|
|
1614
|
-
|
|
1995
|
+
note2("MCP is installed but no projects are exposed. Let's configure that.", "Configuration Needed");
|
|
1615
1996
|
await handleConfigure();
|
|
1616
1997
|
}
|
|
1617
1998
|
let running = true;
|
|
1618
1999
|
while (running) {
|
|
1619
2000
|
const serverStatus = getMCPServerStatus();
|
|
1620
|
-
const serverLabel = serverStatus.running ?
|
|
2001
|
+
const serverLabel = serverStatus.running ? pc3.green("\u25CF Running") : pc3.dim("\u25CB Stopped");
|
|
1621
2002
|
const currentStatus = checkInstallStatus(workspacePath);
|
|
1622
2003
|
const installedCount = [currentStatus.antigravity, currentStatus.claude, currentStatus.vscodeGlobal, currentStatus.vscodeWorkspace].filter(Boolean).length;
|
|
1623
|
-
const action = await
|
|
2004
|
+
const action = await select2({
|
|
1624
2005
|
message: "What would you like to do?",
|
|
1625
2006
|
options: [
|
|
1626
2007
|
{ value: "start", label: `\u25B6\uFE0F Start MCP server`, hint: serverLabel },
|
|
@@ -1631,8 +2012,8 @@ project knowledge in real-time. Let's get you set up.`,
|
|
|
1631
2012
|
{ value: "exit", label: "\u21A9 Exit", hint: "Return to shell" }
|
|
1632
2013
|
]
|
|
1633
2014
|
});
|
|
1634
|
-
if (
|
|
1635
|
-
|
|
2015
|
+
if (isCancel2(action)) {
|
|
2016
|
+
cancel("MCP Hub closed.");
|
|
1636
2017
|
return;
|
|
1637
2018
|
}
|
|
1638
2019
|
switch (action) {
|
|
@@ -1656,7 +2037,7 @@ project knowledge in real-time. Let's get you set up.`,
|
|
|
1656
2037
|
break;
|
|
1657
2038
|
}
|
|
1658
2039
|
}
|
|
1659
|
-
|
|
2040
|
+
outro(pc3.green("MCP Hub closed."));
|
|
1660
2041
|
}
|
|
1661
2042
|
async function handleInstallWizard(workspacePath) {
|
|
1662
2043
|
const status = checkInstallStatus(workspacePath);
|
|
@@ -1664,25 +2045,25 @@ async function handleInstallWizard(workspacePath) {
|
|
|
1664
2045
|
{
|
|
1665
2046
|
value: "antigravity",
|
|
1666
2047
|
label: "Antigravity IDE",
|
|
1667
|
-
hint: status.antigravity ?
|
|
2048
|
+
hint: status.antigravity ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1668
2049
|
},
|
|
1669
2050
|
{
|
|
1670
2051
|
value: "vscode-global",
|
|
1671
|
-
label: "VSCode (Global)",
|
|
1672
|
-
hint: status.vscodeGlobal ?
|
|
2052
|
+
label: "VSCode (Global Settings)",
|
|
2053
|
+
hint: status.vscodeGlobal ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1673
2054
|
},
|
|
1674
2055
|
{
|
|
1675
2056
|
value: "vscode-workspace",
|
|
1676
|
-
label: "VSCode (
|
|
1677
|
-
hint: status.vscodeWorkspace ?
|
|
2057
|
+
label: "VSCode (Workspace Config)",
|
|
2058
|
+
hint: status.vscodeWorkspace ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1678
2059
|
},
|
|
1679
2060
|
{
|
|
1680
2061
|
value: "claude",
|
|
1681
2062
|
label: "Claude Desktop",
|
|
1682
|
-
hint: status.claude ?
|
|
2063
|
+
hint: status.claude ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1683
2064
|
}
|
|
1684
2065
|
];
|
|
1685
|
-
const selected = await
|
|
2066
|
+
const selected = await multiselect({
|
|
1686
2067
|
message: "Select where to install RRCE MCP Server:",
|
|
1687
2068
|
options,
|
|
1688
2069
|
initialValues: [
|
|
@@ -1693,188 +2074,96 @@ async function handleInstallWizard(workspacePath) {
|
|
|
1693
2074
|
],
|
|
1694
2075
|
required: false
|
|
1695
2076
|
});
|
|
1696
|
-
if (
|
|
2077
|
+
if (isCancel2(selected)) return;
|
|
1697
2078
|
const targets = selected;
|
|
1698
2079
|
const results = [];
|
|
1699
2080
|
for (const target of targets) {
|
|
1700
2081
|
const success = installToConfig(target, workspacePath);
|
|
1701
2082
|
const label = getTargetLabel(target);
|
|
1702
|
-
results.push(`${label}: ${success ?
|
|
2083
|
+
results.push(`${label}: ${success ? pc3.green("\u2713 Success") : pc3.red("\u2717 Failed")}`);
|
|
1703
2084
|
}
|
|
1704
2085
|
if (results.length > 0) {
|
|
1705
|
-
|
|
2086
|
+
note2(results.join("\n"), "Installation Results");
|
|
1706
2087
|
}
|
|
1707
2088
|
}
|
|
1708
2089
|
async function handleStartServer() {
|
|
1709
|
-
const
|
|
1710
|
-
const {
|
|
1711
|
-
const
|
|
2090
|
+
const React7 = await import("react");
|
|
2091
|
+
const { render } = await import("ink");
|
|
2092
|
+
const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
|
|
2093
|
+
const { loadMCPConfig: loadMCPConfig2, saveMCPConfig: saveMCPConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2094
|
+
const config = loadMCPConfig2();
|
|
1712
2095
|
const projects = scanForProjects();
|
|
1713
2096
|
const exposedProjects = projects.filter((p) => {
|
|
1714
2097
|
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1715
2098
|
return cfg?.expose ?? config.defaults.includeNew;
|
|
1716
2099
|
});
|
|
1717
2100
|
if (exposedProjects.length === 0) {
|
|
1718
|
-
const shouldConfig = await
|
|
2101
|
+
const shouldConfig = await confirm({
|
|
1719
2102
|
message: "No projects are currently exposed. Configure now?",
|
|
1720
2103
|
initialValue: true
|
|
1721
2104
|
});
|
|
1722
|
-
if (shouldConfig && !
|
|
2105
|
+
if (shouldConfig && !isCancel2(shouldConfig)) {
|
|
1723
2106
|
await handleConfigure();
|
|
1724
2107
|
return handleStartServer();
|
|
1725
2108
|
}
|
|
1726
2109
|
}
|
|
1727
|
-
const
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2110
|
+
const status = getMCPServerStatus();
|
|
2111
|
+
let initialPort = config.server.port;
|
|
2112
|
+
if (!status.running) {
|
|
2113
|
+
const portInput = await text({
|
|
2114
|
+
message: "Select port for MCP Server",
|
|
2115
|
+
initialValue: config.server.port.toString(),
|
|
2116
|
+
placeholder: "3200",
|
|
2117
|
+
validate(value) {
|
|
2118
|
+
if (isNaN(Number(value))) return "Port must be a number";
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
if (isCancel2(portInput)) return;
|
|
2122
|
+
const newPort = parseInt(portInput, 10);
|
|
2123
|
+
if (newPort !== config.server.port) {
|
|
2124
|
+
config.server.port = newPort;
|
|
2125
|
+
saveMCPConfig2(config);
|
|
2126
|
+
initialPort = newPort;
|
|
1733
2127
|
}
|
|
1734
|
-
});
|
|
1735
|
-
if (isCancel6(portInput)) return;
|
|
1736
|
-
const newPort = parseInt(portInput, 10);
|
|
1737
|
-
if (newPort !== config.server.port) {
|
|
1738
|
-
config.server.port = newPort;
|
|
1739
|
-
saveMCPConfig(config);
|
|
1740
2128
|
}
|
|
1741
2129
|
console.clear();
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
};
|
|
1768
|
-
let logBuffer = [];
|
|
1769
|
-
render(logBuffer);
|
|
1770
|
-
try {
|
|
1771
|
-
await startMCPServer();
|
|
1772
|
-
let lastSize = 0;
|
|
1773
|
-
if (fs16.existsSync(logPath)) {
|
|
1774
|
-
const stats = fs16.statSync(logPath);
|
|
1775
|
-
lastSize = stats.size;
|
|
1776
|
-
}
|
|
1777
|
-
let isRunning = true;
|
|
1778
|
-
if (process.stdin.setRawMode) {
|
|
1779
|
-
process.stdin.setRawMode(true);
|
|
1780
|
-
process.stdin.resume();
|
|
1781
|
-
process.stdin.setEncoding("utf8");
|
|
1782
|
-
}
|
|
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
|
-
};
|
|
1795
|
-
const onKey = async (key) => {
|
|
1796
|
-
if (key === "" || key.toLowerCase() === "q") {
|
|
1797
|
-
cleanup();
|
|
1798
|
-
resolve();
|
|
1799
|
-
return;
|
|
1800
|
-
}
|
|
1801
|
-
if (key.toLowerCase() === "p") {
|
|
1802
|
-
cleanup();
|
|
1803
|
-
console.clear();
|
|
1804
|
-
await handleConfigure();
|
|
1805
|
-
resolve();
|
|
1806
|
-
return;
|
|
1807
|
-
}
|
|
1808
|
-
if (key.toLowerCase() === "i") {
|
|
1809
|
-
cleanup();
|
|
1810
|
-
console.clear();
|
|
1811
|
-
await handleInstallWizard(workspacePath);
|
|
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;
|
|
1837
|
-
}
|
|
1838
|
-
};
|
|
1839
|
-
process.stdin.on("data", onKey);
|
|
1840
|
-
const interval = setInterval(() => {
|
|
1841
|
-
if (!isRunning) return;
|
|
1842
|
-
if (fs16.existsSync(logPath)) {
|
|
1843
|
-
const stats = fs16.statSync(logPath);
|
|
1844
|
-
if (stats.size > lastSize) {
|
|
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
|
-
}
|
|
1855
|
-
lastSize = stats.size;
|
|
1856
|
-
render(logBuffer);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
}, 500);
|
|
1860
|
-
});
|
|
1861
|
-
} catch (error) {
|
|
1862
|
-
if (process.stdin.setRawMode) {
|
|
1863
|
-
process.stdin.setRawMode(false);
|
|
2130
|
+
let keepRunning = true;
|
|
2131
|
+
while (keepRunning) {
|
|
2132
|
+
let nextAction = "exit";
|
|
2133
|
+
const app = render(React7.createElement(App2, {
|
|
2134
|
+
initialPort,
|
|
2135
|
+
onExit: () => {
|
|
2136
|
+
nextAction = "exit";
|
|
2137
|
+
},
|
|
2138
|
+
onConfigure: () => {
|
|
2139
|
+
nextAction = "configure";
|
|
2140
|
+
},
|
|
2141
|
+
onInstall: () => {
|
|
2142
|
+
nextAction = "install";
|
|
2143
|
+
}
|
|
2144
|
+
}));
|
|
2145
|
+
await app.waitUntilExit();
|
|
2146
|
+
if (nextAction === "exit") {
|
|
2147
|
+
keepRunning = false;
|
|
2148
|
+
} else if (nextAction === "configure") {
|
|
2149
|
+
console.clear();
|
|
2150
|
+
await handleConfigure();
|
|
2151
|
+
} else if (nextAction === "install") {
|
|
2152
|
+
console.clear();
|
|
2153
|
+
const workspacePath = detectWorkspaceRoot();
|
|
2154
|
+
await handleInstallWizard(workspacePath);
|
|
1864
2155
|
}
|
|
1865
|
-
console.error(pc7.red("\nFailed to start server:"));
|
|
1866
|
-
console.error(error);
|
|
1867
2156
|
}
|
|
1868
2157
|
}
|
|
1869
2158
|
async function handleConfigureGlobalPath() {
|
|
1870
2159
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
1871
|
-
const
|
|
2160
|
+
const fs17 = await import("fs");
|
|
1872
2161
|
const path16 = await import("path");
|
|
1873
|
-
|
|
1874
|
-
`MCP Hub requires a ${
|
|
2162
|
+
note2(
|
|
2163
|
+
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
1875
2164
|
and coordinate across projects.
|
|
1876
2165
|
|
|
1877
|
-
Your current setup uses ${
|
|
2166
|
+
Your current setup uses ${pc3.cyan("workspace")} mode, which stores data
|
|
1878
2167
|
locally in each project. MCP needs a central location.`,
|
|
1879
2168
|
"Global Path Required"
|
|
1880
2169
|
);
|
|
@@ -1883,13 +2172,13 @@ locally in each project. MCP needs a central location.`,
|
|
|
1883
2172
|
return false;
|
|
1884
2173
|
}
|
|
1885
2174
|
try {
|
|
1886
|
-
if (!
|
|
1887
|
-
|
|
2175
|
+
if (!fs17.existsSync(resolvedPath)) {
|
|
2176
|
+
fs17.mkdirSync(resolvedPath, { recursive: true });
|
|
1888
2177
|
}
|
|
1889
2178
|
const config = loadMCPConfig();
|
|
1890
2179
|
saveMCPConfig(config);
|
|
1891
|
-
|
|
1892
|
-
`${
|
|
2180
|
+
note2(
|
|
2181
|
+
`${pc3.green("\u2713")} Global path configured: ${pc3.cyan(resolvedPath)}
|
|
1893
2182
|
|
|
1894
2183
|
MCP config will be stored at:
|
|
1895
2184
|
${path16.join(resolvedPath, "mcp.yaml")}`,
|
|
@@ -1897,15 +2186,15 @@ ${path16.join(resolvedPath, "mcp.yaml")}`,
|
|
|
1897
2186
|
);
|
|
1898
2187
|
return true;
|
|
1899
2188
|
} catch (error) {
|
|
1900
|
-
|
|
1901
|
-
`${
|
|
2189
|
+
note2(
|
|
2190
|
+
`${pc3.red("\u2717")} Failed to create directory: ${error instanceof Error ? error.message : String(error)}`,
|
|
1902
2191
|
"Error"
|
|
1903
2192
|
);
|
|
1904
2193
|
return false;
|
|
1905
2194
|
}
|
|
1906
2195
|
}
|
|
1907
2196
|
async function handleShowStatus() {
|
|
1908
|
-
const s =
|
|
2197
|
+
const s = spinner();
|
|
1909
2198
|
s.start("Loading projects...");
|
|
1910
2199
|
const config = loadMCPConfig();
|
|
1911
2200
|
const projects = scanForProjects();
|
|
@@ -1913,47 +2202,47 @@ async function handleShowStatus() {
|
|
|
1913
2202
|
const installStatus = checkInstallStatus(workspacePath);
|
|
1914
2203
|
s.stop("Projects loaded");
|
|
1915
2204
|
if (projects.length === 0) {
|
|
1916
|
-
|
|
2205
|
+
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
1917
2206
|
return;
|
|
1918
2207
|
}
|
|
1919
2208
|
const lines = [
|
|
1920
|
-
`${
|
|
2209
|
+
`${pc3.bold("Installation Status")}`,
|
|
1921
2210
|
"",
|
|
1922
|
-
` Antigravity: ${installStatus.antigravity ?
|
|
1923
|
-
` VSCode (Global): ${installStatus.vscodeGlobal ?
|
|
1924
|
-
` VSCode (Workspace): ${installStatus.vscodeWorkspace ?
|
|
1925
|
-
` Claude Desktop: ${installStatus.claude ?
|
|
2211
|
+
` Antigravity: ${installStatus.antigravity ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2212
|
+
` VSCode (Global): ${installStatus.vscodeGlobal ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2213
|
+
` VSCode (Workspace): ${installStatus.vscodeWorkspace ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2214
|
+
` Claude Desktop: ${installStatus.claude ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
1926
2215
|
"",
|
|
1927
|
-
`${
|
|
2216
|
+
`${pc3.bold("Project Status")}`,
|
|
1928
2217
|
""
|
|
1929
2218
|
];
|
|
1930
2219
|
for (const project of projects) {
|
|
1931
2220
|
const projectConfig = config.projects.find((p) => p.name === project.name);
|
|
1932
2221
|
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
1933
|
-
const status = isExposed ?
|
|
1934
|
-
const source =
|
|
2222
|
+
const status = isExposed ? pc3.green("\u2713 exposed") : pc3.dim("\u25CB hidden");
|
|
2223
|
+
const source = pc3.dim(`(${project.source})`);
|
|
1935
2224
|
lines.push(` ${status} ${project.name} ${source}`);
|
|
1936
2225
|
}
|
|
1937
2226
|
lines.push("");
|
|
1938
|
-
lines.push(
|
|
2227
|
+
lines.push(pc3.dim(`Config: ${getMCPConfigPath()}`));
|
|
1939
2228
|
const serverStatus = getMCPServerStatus();
|
|
1940
2229
|
if (serverStatus.running) {
|
|
1941
|
-
lines.push(
|
|
2230
|
+
lines.push(pc3.green(`Server: running on port ${serverStatus.port}`));
|
|
1942
2231
|
} else {
|
|
1943
|
-
lines.push(
|
|
2232
|
+
lines.push(pc3.dim("Server: not running"));
|
|
1944
2233
|
}
|
|
1945
|
-
|
|
2234
|
+
note2(lines.join("\n"), "MCP Hub Status");
|
|
1946
2235
|
}
|
|
1947
2236
|
async function handleConfigure() {
|
|
1948
2237
|
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
1949
|
-
const s =
|
|
2238
|
+
const s = spinner();
|
|
1950
2239
|
s.start("Scanning for projects...");
|
|
1951
2240
|
const config = loadMCPConfig();
|
|
1952
2241
|
const projects = scanForProjects();
|
|
1953
2242
|
logger2.info("Configure: Loaded config", { projects: config.projects, defaultMode: config.defaults.includeNew });
|
|
1954
2243
|
s.stop("Projects found");
|
|
1955
2244
|
if (projects.length === 0) {
|
|
1956
|
-
|
|
2245
|
+
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
1957
2246
|
return;
|
|
1958
2247
|
}
|
|
1959
2248
|
const options = projects.map((project) => {
|
|
@@ -1961,7 +2250,7 @@ async function handleConfigure() {
|
|
|
1961
2250
|
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
1962
2251
|
return {
|
|
1963
2252
|
value: project.name,
|
|
1964
|
-
label: `${project.name} ${
|
|
2253
|
+
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
1965
2254
|
hint: project.dataPath
|
|
1966
2255
|
};
|
|
1967
2256
|
});
|
|
@@ -1969,13 +2258,13 @@ async function handleConfigure() {
|
|
|
1969
2258
|
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1970
2259
|
return cfg?.expose ?? config.defaults.includeNew;
|
|
1971
2260
|
}).map((p) => p.name);
|
|
1972
|
-
const selected = await
|
|
2261
|
+
const selected = await multiselect({
|
|
1973
2262
|
message: "Select projects to expose via MCP:",
|
|
1974
2263
|
options,
|
|
1975
2264
|
initialValues: currentlyExposed,
|
|
1976
2265
|
required: false
|
|
1977
2266
|
});
|
|
1978
|
-
if (
|
|
2267
|
+
if (isCancel2(selected)) {
|
|
1979
2268
|
return;
|
|
1980
2269
|
}
|
|
1981
2270
|
const selectedNames = selected;
|
|
@@ -1987,8 +2276,8 @@ async function handleConfigure() {
|
|
|
1987
2276
|
saveMCPConfig(config);
|
|
1988
2277
|
logger2.info("Configure: Config saved", config);
|
|
1989
2278
|
const exposedCount = selectedNames.length;
|
|
1990
|
-
|
|
1991
|
-
`${
|
|
2279
|
+
note2(
|
|
2280
|
+
`${pc3.green("\u2713")} Configuration saved!
|
|
1992
2281
|
|
|
1993
2282
|
Exposed projects: ${exposedCount}
|
|
1994
2283
|
Hidden projects: ${projects.length - exposedCount}`,
|
|
@@ -1998,57 +2287,57 @@ Hidden projects: ${projects.length - exposedCount}`,
|
|
|
1998
2287
|
async function handleStopServer() {
|
|
1999
2288
|
const status = getMCPServerStatus();
|
|
2000
2289
|
if (!status.running) {
|
|
2001
|
-
|
|
2290
|
+
note2("MCP server is not running.", "Status");
|
|
2002
2291
|
return;
|
|
2003
2292
|
}
|
|
2004
|
-
const confirmed = await
|
|
2293
|
+
const confirmed = await confirm({
|
|
2005
2294
|
message: "Stop the MCP server?",
|
|
2006
2295
|
initialValue: true
|
|
2007
2296
|
});
|
|
2008
|
-
if (
|
|
2297
|
+
if (isCancel2(confirmed) || !confirmed) {
|
|
2009
2298
|
return;
|
|
2010
2299
|
}
|
|
2011
2300
|
stopMCPServer();
|
|
2012
|
-
|
|
2301
|
+
note2(pc3.green("MCP server stopped."), "Server Stopped");
|
|
2013
2302
|
}
|
|
2014
2303
|
function showHelp() {
|
|
2015
2304
|
const help = `
|
|
2016
|
-
${
|
|
2305
|
+
${pc3.bold("RRCE MCP Hub")} - Cross-project AI assistant server
|
|
2017
2306
|
|
|
2018
|
-
${
|
|
2307
|
+
${pc3.bold("ABOUT")}
|
|
2019
2308
|
MCP (Model Context Protocol) allows AI assistants like Claude to
|
|
2020
2309
|
access your project knowledge in real-time. The RRCE MCP Hub
|
|
2021
2310
|
provides a central server that exposes selected projects.
|
|
2022
2311
|
|
|
2023
|
-
${
|
|
2024
|
-
${
|
|
2025
|
-
${
|
|
2026
|
-
${
|
|
2027
|
-
${
|
|
2312
|
+
${pc3.bold("MENU OPTIONS")}
|
|
2313
|
+
${pc3.cyan("Start MCP server")} Start the server for AI access
|
|
2314
|
+
${pc3.cyan("Configure projects")} Choose which projects to expose
|
|
2315
|
+
${pc3.cyan("Install to IDE")} Add to Antigravity, VSCode, or Claude
|
|
2316
|
+
${pc3.cyan("View status")} See which projects are exposed
|
|
2028
2317
|
|
|
2029
|
-
${
|
|
2030
|
-
${
|
|
2031
|
-
${
|
|
2032
|
-
${
|
|
2033
|
-
${
|
|
2318
|
+
${pc3.bold("DIRECT COMMANDS")}
|
|
2319
|
+
${pc3.dim("rrce-workflow mcp start")} Start server directly
|
|
2320
|
+
${pc3.dim("rrce-workflow mcp stop")} Stop server directly
|
|
2321
|
+
${pc3.dim("rrce-workflow mcp status")} Show status directly
|
|
2322
|
+
${pc3.dim("rrce-workflow mcp help")} Show this help
|
|
2034
2323
|
|
|
2035
|
-
${
|
|
2036
|
-
${
|
|
2037
|
-
${
|
|
2038
|
-
${
|
|
2039
|
-
${
|
|
2324
|
+
${pc3.bold("IDE INSTALLATION")}
|
|
2325
|
+
${pc3.cyan("Antigravity")} ~/.gemini/antigravity/mcp_config.json
|
|
2326
|
+
${pc3.cyan("VSCode Global")} ~/.config/Code/User/settings.json
|
|
2327
|
+
${pc3.cyan("VSCode Workspace")} .vscode/mcp.json
|
|
2328
|
+
${pc3.cyan("Claude Desktop")} ~/.config/claude/claude_desktop_config.json
|
|
2040
2329
|
|
|
2041
|
-
${
|
|
2042
|
-
${
|
|
2043
|
-
${
|
|
2044
|
-
${
|
|
2330
|
+
${pc3.bold("SERVER COMMANDS")} (while running)
|
|
2331
|
+
${pc3.cyan("q")} Stop and quit ${pc3.cyan("p")} Reconfigure projects
|
|
2332
|
+
${pc3.cyan("i")} Install to IDE ${pc3.cyan("r")} Reload config
|
|
2333
|
+
${pc3.cyan("c")} Clear logs ${pc3.cyan("?")} Show help
|
|
2045
2334
|
|
|
2046
|
-
${
|
|
2047
|
-
${
|
|
2048
|
-
${
|
|
2049
|
-
${
|
|
2335
|
+
${pc3.bold("RESOURCES EXPOSED")}
|
|
2336
|
+
${pc3.cyan("rrce://projects")} List all exposed projects
|
|
2337
|
+
${pc3.cyan("rrce://projects/{name}/context")} Get project context
|
|
2338
|
+
${pc3.cyan("rrce://projects/{name}/tasks")} Get project tasks
|
|
2050
2339
|
`;
|
|
2051
|
-
|
|
2340
|
+
note2(help.trim(), "Help");
|
|
2052
2341
|
}
|
|
2053
2342
|
var init_mcp = __esm({
|
|
2054
2343
|
"src/mcp/index.ts"() {
|
|
@@ -2061,154 +2350,16 @@ var init_mcp = __esm({
|
|
|
2061
2350
|
}
|
|
2062
2351
|
});
|
|
2063
2352
|
|
|
2064
|
-
// src/commands/wizard/index.ts
|
|
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";
|
|
2068
|
-
|
|
2069
|
-
// src/lib/git.ts
|
|
2070
|
-
import { execSync } from "child_process";
|
|
2071
|
-
function getGitUser() {
|
|
2072
|
-
try {
|
|
2073
|
-
const result = execSync("git config user.name", { encoding: "utf-8" });
|
|
2074
|
-
return result.trim() || null;
|
|
2075
|
-
} catch {
|
|
2076
|
-
return null;
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
// src/commands/wizard/index.ts
|
|
2081
|
-
init_paths();
|
|
2082
|
-
init_detection();
|
|
2083
|
-
|
|
2084
2353
|
// src/commands/wizard/setup-flow.ts
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
import
|
|
2088
|
-
import
|
|
2089
|
-
import * as fs7 from "fs";
|
|
2090
|
-
import * as path8 from "path";
|
|
2091
|
-
|
|
2092
|
-
// src/commands/wizard/utils.ts
|
|
2093
|
-
init_paths();
|
|
2094
|
-
import * as fs4 from "fs";
|
|
2095
|
-
import * as path4 from "path";
|
|
2096
|
-
function copyPromptsToDir(prompts, targetDir, extension) {
|
|
2097
|
-
for (const prompt of prompts) {
|
|
2098
|
-
const baseName = path4.basename(prompt.filePath, ".md");
|
|
2099
|
-
const targetName = baseName + extension;
|
|
2100
|
-
const targetPath = path4.join(targetDir, targetName);
|
|
2101
|
-
const content = fs4.readFileSync(prompt.filePath, "utf-8");
|
|
2102
|
-
fs4.writeFileSync(targetPath, content);
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
function copyDirRecursive(src, dest) {
|
|
2106
|
-
const entries = fs4.readdirSync(src, { withFileTypes: true });
|
|
2107
|
-
for (const entry of entries) {
|
|
2108
|
-
const srcPath = path4.join(src, entry.name);
|
|
2109
|
-
const destPath = path4.join(dest, entry.name);
|
|
2110
|
-
if (entry.isDirectory()) {
|
|
2111
|
-
ensureDir(destPath);
|
|
2112
|
-
copyDirRecursive(srcPath, destPath);
|
|
2113
|
-
} else {
|
|
2114
|
-
fs4.copyFileSync(srcPath, destPath);
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
// src/commands/wizard/vscode.ts
|
|
2120
|
-
init_paths();
|
|
2121
|
-
init_detection();
|
|
2122
|
-
import * as fs5 from "fs";
|
|
2123
|
-
import * as path5 from "path";
|
|
2124
|
-
function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
2125
|
-
const workspaceFilePath = path5.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
2126
|
-
let workspace;
|
|
2127
|
-
if (fs5.existsSync(workspaceFilePath)) {
|
|
2128
|
-
try {
|
|
2129
|
-
const content = fs5.readFileSync(workspaceFilePath, "utf-8");
|
|
2130
|
-
workspace = JSON.parse(content);
|
|
2131
|
-
} catch {
|
|
2132
|
-
workspace = { folders: [], settings: {} };
|
|
2133
|
-
}
|
|
2134
|
-
} else {
|
|
2135
|
-
workspace = { folders: [], settings: {} };
|
|
2136
|
-
}
|
|
2137
|
-
if (!workspace.settings) {
|
|
2138
|
-
workspace.settings = {};
|
|
2139
|
-
}
|
|
2140
|
-
workspace.folders = workspace.folders.filter(
|
|
2141
|
-
(f) => f.path === "." || !f.name?.startsWith("\u{1F4C1}") && !f.name?.startsWith("\u{1F4DA}") && !f.name?.startsWith("\u{1F4CE}") && !f.name?.startsWith("\u{1F4CB}")
|
|
2142
|
-
);
|
|
2143
|
-
const mainFolderIndex = workspace.folders.findIndex((f) => f.path === ".");
|
|
2144
|
-
if (mainFolderIndex === -1) {
|
|
2145
|
-
workspace.folders.unshift({
|
|
2146
|
-
path: ".",
|
|
2147
|
-
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
2148
|
-
});
|
|
2149
|
-
} else {
|
|
2150
|
-
workspace.folders[mainFolderIndex] = {
|
|
2151
|
-
path: ".",
|
|
2152
|
-
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
2153
|
-
};
|
|
2154
|
-
}
|
|
2155
|
-
const referenceFolderPaths = [];
|
|
2156
|
-
const isDetectedProjects = linkedProjects.length > 0 && typeof linkedProjects[0] === "object";
|
|
2157
|
-
if (isDetectedProjects) {
|
|
2158
|
-
const projects = linkedProjects;
|
|
2159
|
-
for (const project of projects) {
|
|
2160
|
-
const sourceLabel = project.source === "global" ? "global" : "local";
|
|
2161
|
-
const folderPath = project.dataPath;
|
|
2162
|
-
if (fs5.existsSync(folderPath)) {
|
|
2163
|
-
referenceFolderPaths.push(folderPath);
|
|
2164
|
-
workspace.folders.push({
|
|
2165
|
-
path: folderPath,
|
|
2166
|
-
name: `\u{1F4C1} ${project.name} [${sourceLabel}]`
|
|
2167
|
-
});
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
} else {
|
|
2171
|
-
const projectNames = linkedProjects;
|
|
2172
|
-
const rrceHome = customGlobalPath || getRRCEHome();
|
|
2173
|
-
for (const projectName of projectNames) {
|
|
2174
|
-
const folderPath = path5.join(rrceHome, "workspaces", projectName);
|
|
2175
|
-
if (fs5.existsSync(folderPath)) {
|
|
2176
|
-
referenceFolderPaths.push(folderPath);
|
|
2177
|
-
workspace.folders.push({
|
|
2178
|
-
path: folderPath,
|
|
2179
|
-
name: `\u{1F4C1} ${projectName} [global]`
|
|
2180
|
-
});
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
if (referenceFolderPaths.length > 0) {
|
|
2185
|
-
const readonlyPatterns = {};
|
|
2186
|
-
for (const folderPath of referenceFolderPaths) {
|
|
2187
|
-
readonlyPatterns[`${folderPath}/**`] = true;
|
|
2188
|
-
}
|
|
2189
|
-
const existingReadonly = workspace.settings["files.readonlyInclude"] || {};
|
|
2190
|
-
const cleanedReadonly = {};
|
|
2191
|
-
for (const [pattern, value] of Object.entries(existingReadonly)) {
|
|
2192
|
-
if (!pattern.includes(".rrce-workflow") && !pattern.includes("rrce-workflow/workspaces")) {
|
|
2193
|
-
cleanedReadonly[pattern] = value;
|
|
2194
|
-
}
|
|
2195
|
-
}
|
|
2196
|
-
workspace.settings["files.readonlyInclude"] = {
|
|
2197
|
-
...cleanedReadonly,
|
|
2198
|
-
...readonlyPatterns
|
|
2199
|
-
};
|
|
2200
|
-
}
|
|
2201
|
-
fs5.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
2202
|
-
}
|
|
2203
|
-
|
|
2204
|
-
// src/commands/wizard/setup-flow.ts
|
|
2205
|
-
init_detection();
|
|
2206
|
-
init_tui_utils();
|
|
2354
|
+
import { group, select as select3, multiselect as multiselect2, confirm as confirm2, spinner as spinner2, note as note3, outro as outro2, cancel as cancel2, isCancel as isCancel3 } from "@clack/prompts";
|
|
2355
|
+
import pc4 from "picocolors";
|
|
2356
|
+
import * as fs12 from "fs";
|
|
2357
|
+
import * as path12 from "path";
|
|
2207
2358
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
2208
|
-
const s =
|
|
2359
|
+
const s = spinner2();
|
|
2209
2360
|
const config = await group(
|
|
2210
2361
|
{
|
|
2211
|
-
storageMode: () =>
|
|
2362
|
+
storageMode: () => select3({
|
|
2212
2363
|
message: "Where should workflow data be stored?",
|
|
2213
2364
|
options: [
|
|
2214
2365
|
{ value: "global", label: "Global (~/.rrce-workflow/)", hint: "Cross-project access, clean workspace" },
|
|
@@ -2216,7 +2367,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2216
2367
|
],
|
|
2217
2368
|
initialValue: "global"
|
|
2218
2369
|
}),
|
|
2219
|
-
tools: () =>
|
|
2370
|
+
tools: () => multiselect2({
|
|
2220
2371
|
message: "Which AI tools do you use?",
|
|
2221
2372
|
options: [
|
|
2222
2373
|
{ value: "copilot", label: "GitHub Copilot", hint: "VSCode" },
|
|
@@ -2228,44 +2379,44 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2228
2379
|
if (existingProjects.length === 0) {
|
|
2229
2380
|
return Promise.resolve([]);
|
|
2230
2381
|
}
|
|
2231
|
-
return
|
|
2382
|
+
return multiselect2({
|
|
2232
2383
|
message: "Link knowledge from other projects?",
|
|
2233
2384
|
options: existingProjects.map((project) => ({
|
|
2234
2385
|
value: `${project.name}:${project.source}`,
|
|
2235
2386
|
// Unique key
|
|
2236
|
-
label: `${project.name} ${
|
|
2237
|
-
hint:
|
|
2387
|
+
label: `${project.name} ${pc4.dim(`(${project.source})`)}`,
|
|
2388
|
+
hint: pc4.dim(
|
|
2238
2389
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
2239
2390
|
)
|
|
2240
2391
|
})),
|
|
2241
2392
|
required: false
|
|
2242
2393
|
});
|
|
2243
2394
|
},
|
|
2244
|
-
addToGitignore: () =>
|
|
2395
|
+
addToGitignore: () => confirm2({
|
|
2245
2396
|
message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
|
|
2246
2397
|
initialValue: true
|
|
2247
2398
|
}),
|
|
2248
|
-
confirm: () =>
|
|
2399
|
+
confirm: () => confirm2({
|
|
2249
2400
|
message: "Create configuration?",
|
|
2250
2401
|
initialValue: true
|
|
2251
2402
|
})
|
|
2252
2403
|
},
|
|
2253
2404
|
{
|
|
2254
2405
|
onCancel: () => {
|
|
2255
|
-
|
|
2406
|
+
cancel2("Setup process cancelled.");
|
|
2256
2407
|
process.exit(0);
|
|
2257
2408
|
}
|
|
2258
2409
|
}
|
|
2259
2410
|
);
|
|
2260
2411
|
if (!config.confirm) {
|
|
2261
|
-
|
|
2412
|
+
outro2("Setup cancelled by user.");
|
|
2262
2413
|
process.exit(0);
|
|
2263
2414
|
}
|
|
2264
2415
|
let customGlobalPath;
|
|
2265
2416
|
if (config.storageMode === "global") {
|
|
2266
2417
|
customGlobalPath = await resolveGlobalPath();
|
|
2267
2418
|
if (!customGlobalPath) {
|
|
2268
|
-
|
|
2419
|
+
cancel2("Setup cancelled - no writable global path available.");
|
|
2269
2420
|
process.exit(1);
|
|
2270
2421
|
}
|
|
2271
2422
|
}
|
|
@@ -2289,7 +2440,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2289
2440
|
`Storage: ${config.storageMode}`
|
|
2290
2441
|
];
|
|
2291
2442
|
if (customGlobalPath && customGlobalPath !== getDefaultRRCEHome()) {
|
|
2292
|
-
summary.push(`Global path: ${
|
|
2443
|
+
summary.push(`Global path: ${pc4.cyan(customGlobalPath)}`);
|
|
2293
2444
|
}
|
|
2294
2445
|
if (dataPaths.length > 0) {
|
|
2295
2446
|
summary.push(`Data paths:`);
|
|
@@ -2302,17 +2453,26 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2302
2453
|
const linkedProjects = config.linkedProjects;
|
|
2303
2454
|
if (linkedProjects.length > 0) {
|
|
2304
2455
|
summary.push(`Linked projects: ${linkedProjects.join(", ")}`);
|
|
2305
|
-
summary.push(`Workspace file: ${
|
|
2456
|
+
summary.push(`Workspace file: ${pc4.cyan(`${workspaceName}.code-workspace`)}`);
|
|
2306
2457
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2458
|
+
note3(summary.join("\n"), "Setup Summary");
|
|
2459
|
+
const shouldConfigureMCP = await confirm2({
|
|
2460
|
+
message: "Would you like to configure the MCP server now?",
|
|
2461
|
+
initialValue: true
|
|
2462
|
+
});
|
|
2463
|
+
if (shouldConfigureMCP && !isCancel3(shouldConfigureMCP)) {
|
|
2464
|
+
const { runMCP: runMCP2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
2465
|
+
await runMCP2();
|
|
2310
2466
|
} else {
|
|
2311
|
-
|
|
2467
|
+
if (linkedProjects.length > 0) {
|
|
2468
|
+
outro2(pc4.green(`\u2713 Setup complete! Open ${pc4.bold(`${workspaceName}.code-workspace`)} in VSCode to access linked knowledge.`));
|
|
2469
|
+
} else {
|
|
2470
|
+
outro2(pc4.green(`\u2713 Setup complete! Your agents are ready to use.`));
|
|
2471
|
+
}
|
|
2312
2472
|
}
|
|
2313
2473
|
} catch (error) {
|
|
2314
2474
|
s.stop("Error occurred");
|
|
2315
|
-
|
|
2475
|
+
cancel2(`Failed to setup: ${error instanceof Error ? error.message : String(error)}`);
|
|
2316
2476
|
process.exit(1);
|
|
2317
2477
|
}
|
|
2318
2478
|
}
|
|
@@ -2320,14 +2480,14 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
2320
2480
|
const dataPaths = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
|
|
2321
2481
|
for (const dataPath of dataPaths) {
|
|
2322
2482
|
ensureDir(dataPath);
|
|
2323
|
-
ensureDir(
|
|
2324
|
-
ensureDir(
|
|
2325
|
-
ensureDir(
|
|
2326
|
-
ensureDir(
|
|
2483
|
+
ensureDir(path12.join(dataPath, "knowledge"));
|
|
2484
|
+
ensureDir(path12.join(dataPath, "refs"));
|
|
2485
|
+
ensureDir(path12.join(dataPath, "tasks"));
|
|
2486
|
+
ensureDir(path12.join(dataPath, "templates"));
|
|
2327
2487
|
}
|
|
2328
2488
|
const agentCoreDir = getAgentCoreDir();
|
|
2329
2489
|
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
2330
|
-
copyDirToAllStoragePaths(
|
|
2490
|
+
copyDirToAllStoragePaths(path12.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
2331
2491
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
2332
2492
|
if (config.tools.includes("copilot")) {
|
|
2333
2493
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
@@ -2339,8 +2499,8 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
2339
2499
|
ensureDir(antigravityPath);
|
|
2340
2500
|
copyPromptsToDir(prompts, antigravityPath, ".md");
|
|
2341
2501
|
}
|
|
2342
|
-
const workspaceConfigPath =
|
|
2343
|
-
ensureDir(
|
|
2502
|
+
const workspaceConfigPath = path12.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
2503
|
+
ensureDir(path12.dirname(workspaceConfigPath));
|
|
2344
2504
|
let configContent = `# RRCE-Workflow Configuration
|
|
2345
2505
|
version: 1
|
|
2346
2506
|
|
|
@@ -2368,7 +2528,7 @@ linked_projects:
|
|
|
2368
2528
|
`;
|
|
2369
2529
|
});
|
|
2370
2530
|
}
|
|
2371
|
-
|
|
2531
|
+
fs12.writeFileSync(workspaceConfigPath, configContent);
|
|
2372
2532
|
if (config.addToGitignore) {
|
|
2373
2533
|
updateGitignore(workspacePath, config.storageMode, config.tools);
|
|
2374
2534
|
}
|
|
@@ -2380,8 +2540,8 @@ linked_projects:
|
|
|
2380
2540
|
}
|
|
2381
2541
|
}
|
|
2382
2542
|
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
2383
|
-
const globalPath =
|
|
2384
|
-
const workspacePath =
|
|
2543
|
+
const globalPath = path12.join(customGlobalPath || getDefaultRRCEHome(), "workspaces", workspaceName);
|
|
2544
|
+
const workspacePath = path12.join(workspaceRoot, ".rrce-workflow");
|
|
2385
2545
|
switch (mode) {
|
|
2386
2546
|
case "global":
|
|
2387
2547
|
return [globalPath];
|
|
@@ -2392,7 +2552,7 @@ function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
|
2392
2552
|
}
|
|
2393
2553
|
}
|
|
2394
2554
|
function updateGitignore(workspacePath, storageMode, tools) {
|
|
2395
|
-
const gitignorePath =
|
|
2555
|
+
const gitignorePath = path12.join(workspacePath, ".gitignore");
|
|
2396
2556
|
const entries = [];
|
|
2397
2557
|
if (storageMode === "workspace") {
|
|
2398
2558
|
entries.push(".rrce-workflow/");
|
|
@@ -2408,8 +2568,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2408
2568
|
}
|
|
2409
2569
|
try {
|
|
2410
2570
|
let content = "";
|
|
2411
|
-
if (
|
|
2412
|
-
content =
|
|
2571
|
+
if (fs12.existsSync(gitignorePath)) {
|
|
2572
|
+
content = fs12.readFileSync(gitignorePath, "utf-8");
|
|
2413
2573
|
}
|
|
2414
2574
|
const lines = content.split("\n").map((line) => line.trim());
|
|
2415
2575
|
const newEntries = [];
|
|
@@ -2434,57 +2594,66 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2434
2594
|
newContent += "\n# rrce-workflow generated folders (uncomment to ignore)\n";
|
|
2435
2595
|
}
|
|
2436
2596
|
newContent += newEntries.map((e) => `# ${e}`).join("\n") + "\n";
|
|
2437
|
-
|
|
2597
|
+
fs12.writeFileSync(gitignorePath, newContent);
|
|
2438
2598
|
return true;
|
|
2439
2599
|
} catch {
|
|
2440
2600
|
return false;
|
|
2441
2601
|
}
|
|
2442
2602
|
}
|
|
2603
|
+
var init_setup_flow = __esm({
|
|
2604
|
+
"src/commands/wizard/setup-flow.ts"() {
|
|
2605
|
+
"use strict";
|
|
2606
|
+
init_paths();
|
|
2607
|
+
init_prompts();
|
|
2608
|
+
init_utils();
|
|
2609
|
+
init_vscode();
|
|
2610
|
+
init_detection();
|
|
2611
|
+
init_tui_utils();
|
|
2612
|
+
}
|
|
2613
|
+
});
|
|
2443
2614
|
|
|
2444
2615
|
// src/commands/wizard/link-flow.ts
|
|
2445
|
-
|
|
2446
|
-
import
|
|
2447
|
-
import
|
|
2448
|
-
import * as fs8 from "fs";
|
|
2449
|
-
init_detection();
|
|
2616
|
+
import { multiselect as multiselect3, spinner as spinner3, note as note4, outro as outro3, cancel as cancel3, isCancel as isCancel4 } from "@clack/prompts";
|
|
2617
|
+
import pc5 from "picocolors";
|
|
2618
|
+
import * as fs13 from "fs";
|
|
2450
2619
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
2451
2620
|
const projects = scanForProjects({
|
|
2452
2621
|
excludeWorkspace: workspaceName,
|
|
2453
2622
|
workspacePath
|
|
2454
2623
|
});
|
|
2455
2624
|
if (projects.length === 0) {
|
|
2456
|
-
|
|
2625
|
+
outro3(pc5.yellow("No other projects found. Try setting up another project first."));
|
|
2457
2626
|
return;
|
|
2458
2627
|
}
|
|
2459
2628
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2460
|
-
const linkedProjects = await
|
|
2629
|
+
const linkedProjects = await multiselect3({
|
|
2461
2630
|
message: "Select projects to link:",
|
|
2462
2631
|
options: projects.map((project) => ({
|
|
2463
2632
|
value: `${project.name}:${project.source}`,
|
|
2464
2633
|
// Unique key
|
|
2465
|
-
label: `${project.name} ${
|
|
2466
|
-
hint:
|
|
2634
|
+
label: `${project.name} ${pc5.dim(`(${project.source})`)}`,
|
|
2635
|
+
hint: pc5.dim(
|
|
2467
2636
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
2468
2637
|
)
|
|
2469
2638
|
})),
|
|
2470
2639
|
required: true
|
|
2471
2640
|
});
|
|
2472
|
-
if (
|
|
2473
|
-
|
|
2641
|
+
if (isCancel4(linkedProjects)) {
|
|
2642
|
+
cancel3("Cancelled.");
|
|
2474
2643
|
process.exit(0);
|
|
2475
2644
|
}
|
|
2476
2645
|
const selectedKeys = linkedProjects;
|
|
2477
2646
|
if (selectedKeys.length === 0) {
|
|
2478
|
-
|
|
2647
|
+
outro3("No projects selected.");
|
|
2479
2648
|
return;
|
|
2480
2649
|
}
|
|
2481
2650
|
const selectedProjects = projects.filter(
|
|
2482
2651
|
(p) => selectedKeys.includes(`${p.name}:${p.source}`)
|
|
2483
2652
|
);
|
|
2484
|
-
const s =
|
|
2653
|
+
const s = spinner3();
|
|
2485
2654
|
s.start("Linking projects");
|
|
2486
2655
|
const configFilePath = getConfigPath(workspacePath);
|
|
2487
|
-
let configContent =
|
|
2656
|
+
let configContent = fs13.readFileSync(configFilePath, "utf-8");
|
|
2488
2657
|
if (configContent.includes("linked_projects:")) {
|
|
2489
2658
|
const lines = configContent.split("\n");
|
|
2490
2659
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -2511,60 +2680,67 @@ linked_projects:
|
|
|
2511
2680
|
`;
|
|
2512
2681
|
});
|
|
2513
2682
|
}
|
|
2514
|
-
|
|
2683
|
+
fs13.writeFileSync(configFilePath, configContent);
|
|
2515
2684
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
2516
2685
|
s.stop("Projects linked");
|
|
2517
2686
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
2518
2687
|
const summary = [
|
|
2519
2688
|
`Linked projects:`,
|
|
2520
|
-
...selectedProjects.map((p) => ` \u2713 ${p.name} ${
|
|
2689
|
+
...selectedProjects.map((p) => ` \u2713 ${p.name} ${pc5.dim(`(${p.source})`)}`),
|
|
2521
2690
|
``,
|
|
2522
|
-
`Workspace file: ${
|
|
2691
|
+
`Workspace file: ${pc5.cyan(workspaceFile)}`
|
|
2523
2692
|
];
|
|
2524
|
-
|
|
2525
|
-
|
|
2693
|
+
note4(summary.join("\n"), "Link Summary");
|
|
2694
|
+
outro3(pc5.green(`\u2713 Projects linked! Open ${pc5.bold(workspaceFile)} in VSCode to access linked data.`));
|
|
2526
2695
|
}
|
|
2696
|
+
var init_link_flow = __esm({
|
|
2697
|
+
"src/commands/wizard/link-flow.ts"() {
|
|
2698
|
+
"use strict";
|
|
2699
|
+
init_paths();
|
|
2700
|
+
init_vscode();
|
|
2701
|
+
init_detection();
|
|
2702
|
+
}
|
|
2703
|
+
});
|
|
2527
2704
|
|
|
2528
2705
|
// src/commands/wizard/sync-flow.ts
|
|
2529
|
-
|
|
2530
|
-
import
|
|
2531
|
-
import
|
|
2532
|
-
import * as
|
|
2533
|
-
import * as path9 from "path";
|
|
2706
|
+
import { confirm as confirm3, spinner as spinner4, note as note5, outro as outro4, cancel as cancel4, isCancel as isCancel5 } from "@clack/prompts";
|
|
2707
|
+
import pc6 from "picocolors";
|
|
2708
|
+
import * as fs14 from "fs";
|
|
2709
|
+
import * as path13 from "path";
|
|
2534
2710
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
2535
2711
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
2536
2712
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2537
|
-
const globalPath =
|
|
2713
|
+
const globalPath = path13.join(customGlobalPath, "workspaces", workspaceName);
|
|
2538
2714
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
2539
2715
|
const existingDirs = subdirs.filter(
|
|
2540
|
-
(dir) =>
|
|
2716
|
+
(dir) => fs14.existsSync(path13.join(localPath, dir))
|
|
2541
2717
|
);
|
|
2542
2718
|
if (existingDirs.length === 0) {
|
|
2543
|
-
|
|
2719
|
+
outro4(pc6.yellow("No data found in workspace storage to sync."));
|
|
2544
2720
|
return;
|
|
2545
2721
|
}
|
|
2546
|
-
|
|
2722
|
+
note5(
|
|
2547
2723
|
`The following will be copied to global storage:
|
|
2548
2724
|
${existingDirs.map((d) => ` \u2022 ${d}/`).join("\n")}
|
|
2549
2725
|
|
|
2550
|
-
Destination: ${
|
|
2726
|
+
Destination: ${pc6.cyan(globalPath)}`,
|
|
2551
2727
|
"Sync Preview"
|
|
2552
2728
|
);
|
|
2553
|
-
const shouldSync = await
|
|
2729
|
+
const shouldSync = await confirm3({
|
|
2554
2730
|
message: "Proceed with sync to global storage?",
|
|
2555
2731
|
initialValue: true
|
|
2556
2732
|
});
|
|
2557
|
-
if (
|
|
2558
|
-
|
|
2733
|
+
if (isCancel5(shouldSync) || !shouldSync) {
|
|
2734
|
+
outro4("Sync cancelled.");
|
|
2559
2735
|
return;
|
|
2560
2736
|
}
|
|
2561
|
-
const s =
|
|
2737
|
+
const s = spinner4();
|
|
2562
2738
|
s.start("Syncing to global storage");
|
|
2563
2739
|
try {
|
|
2564
2740
|
ensureDir(globalPath);
|
|
2565
2741
|
for (const dir of existingDirs) {
|
|
2566
|
-
const srcDir =
|
|
2567
|
-
const destDir =
|
|
2742
|
+
const srcDir = path13.join(localPath, dir);
|
|
2743
|
+
const destDir = path13.join(globalPath, dir);
|
|
2568
2744
|
ensureDir(destDir);
|
|
2569
2745
|
copyDirRecursive(srcDir, destDir);
|
|
2570
2746
|
}
|
|
@@ -2573,28 +2749,33 @@ Destination: ${pc5.cyan(globalPath)}`,
|
|
|
2573
2749
|
`Synced directories:`,
|
|
2574
2750
|
...existingDirs.map((d) => ` \u2713 ${d}/`),
|
|
2575
2751
|
``,
|
|
2576
|
-
`Global path: ${
|
|
2752
|
+
`Global path: ${pc6.cyan(globalPath)}`,
|
|
2577
2753
|
``,
|
|
2578
2754
|
`Other projects can now link this knowledge!`
|
|
2579
2755
|
];
|
|
2580
|
-
|
|
2581
|
-
|
|
2756
|
+
note5(summary.join("\n"), "Sync Summary");
|
|
2757
|
+
outro4(pc6.green("\u2713 Workspace knowledge synced to global storage!"));
|
|
2582
2758
|
} catch (error) {
|
|
2583
2759
|
s.stop("Error occurred");
|
|
2584
|
-
|
|
2760
|
+
cancel4(`Failed to sync: ${error instanceof Error ? error.message : String(error)}`);
|
|
2585
2761
|
process.exit(1);
|
|
2586
2762
|
}
|
|
2587
2763
|
}
|
|
2764
|
+
var init_sync_flow = __esm({
|
|
2765
|
+
"src/commands/wizard/sync-flow.ts"() {
|
|
2766
|
+
"use strict";
|
|
2767
|
+
init_paths();
|
|
2768
|
+
init_utils();
|
|
2769
|
+
}
|
|
2770
|
+
});
|
|
2588
2771
|
|
|
2589
2772
|
// src/commands/wizard/update-flow.ts
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
import
|
|
2593
|
-
import
|
|
2594
|
-
import * as fs10 from "fs";
|
|
2595
|
-
import * as path10 from "path";
|
|
2773
|
+
import { confirm as confirm4, spinner as spinner5, note as note6, outro as outro5, cancel as cancel5, isCancel as isCancel6 } from "@clack/prompts";
|
|
2774
|
+
import pc7 from "picocolors";
|
|
2775
|
+
import * as fs15 from "fs";
|
|
2776
|
+
import * as path14 from "path";
|
|
2596
2777
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
2597
|
-
const s =
|
|
2778
|
+
const s = spinner5();
|
|
2598
2779
|
s.start("Checking for updates");
|
|
2599
2780
|
try {
|
|
2600
2781
|
const agentCoreDir = getAgentCoreDir();
|
|
@@ -2603,7 +2784,7 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
|
2603
2784
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2604
2785
|
const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
|
|
2605
2786
|
s.stop("Updates found");
|
|
2606
|
-
|
|
2787
|
+
note6(
|
|
2607
2788
|
`The following will be updated from the package:
|
|
2608
2789
|
\u2022 prompts/ (${prompts.length} agent prompts)
|
|
2609
2790
|
\u2022 templates/ (output templates)
|
|
@@ -2612,20 +2793,20 @@ Target locations:
|
|
|
2612
2793
|
${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
2613
2794
|
"Update Preview"
|
|
2614
2795
|
);
|
|
2615
|
-
const shouldUpdate = await
|
|
2796
|
+
const shouldUpdate = await confirm4({
|
|
2616
2797
|
message: "Proceed with update?",
|
|
2617
2798
|
initialValue: true
|
|
2618
2799
|
});
|
|
2619
|
-
if (
|
|
2620
|
-
|
|
2800
|
+
if (isCancel6(shouldUpdate) || !shouldUpdate) {
|
|
2801
|
+
outro5("Update cancelled.");
|
|
2621
2802
|
return;
|
|
2622
2803
|
}
|
|
2623
2804
|
s.start("Updating from package");
|
|
2624
2805
|
for (const dataPath of dataPaths) {
|
|
2625
|
-
copyDirToAllStoragePaths(
|
|
2806
|
+
copyDirToAllStoragePaths(path14.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
2626
2807
|
}
|
|
2627
2808
|
const configFilePath = getConfigPath(workspacePath);
|
|
2628
|
-
const configContent =
|
|
2809
|
+
const configContent = fs15.readFileSync(configFilePath, "utf-8");
|
|
2629
2810
|
if (configContent.includes("copilot: true")) {
|
|
2630
2811
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
2631
2812
|
ensureDir(copilotPath);
|
|
@@ -2644,17 +2825,17 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
2644
2825
|
``,
|
|
2645
2826
|
`Your configuration and knowledge files were preserved.`
|
|
2646
2827
|
];
|
|
2647
|
-
|
|
2648
|
-
|
|
2828
|
+
note6(summary.join("\n"), "Update Summary");
|
|
2829
|
+
outro5(pc7.green("\u2713 Successfully updated from package!"));
|
|
2649
2830
|
} catch (error) {
|
|
2650
2831
|
s.stop("Error occurred");
|
|
2651
|
-
|
|
2832
|
+
cancel5(`Failed to update: ${error instanceof Error ? error.message : String(error)}`);
|
|
2652
2833
|
process.exit(1);
|
|
2653
2834
|
}
|
|
2654
2835
|
}
|
|
2655
2836
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
2656
|
-
const globalPath =
|
|
2657
|
-
const workspacePath =
|
|
2837
|
+
const globalPath = path14.join(customGlobalPath, "workspaces", workspaceName);
|
|
2838
|
+
const workspacePath = path14.join(workspaceRoot, ".rrce-workflow");
|
|
2658
2839
|
switch (mode) {
|
|
2659
2840
|
case "global":
|
|
2660
2841
|
return [globalPath];
|
|
@@ -2664,9 +2845,23 @@ function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot,
|
|
|
2664
2845
|
return [globalPath];
|
|
2665
2846
|
}
|
|
2666
2847
|
}
|
|
2848
|
+
var init_update_flow = __esm({
|
|
2849
|
+
"src/commands/wizard/update-flow.ts"() {
|
|
2850
|
+
"use strict";
|
|
2851
|
+
init_paths();
|
|
2852
|
+
init_prompts();
|
|
2853
|
+
init_utils();
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2667
2856
|
|
|
2668
2857
|
// src/commands/wizard/index.ts
|
|
2669
|
-
|
|
2858
|
+
var wizard_exports = {};
|
|
2859
|
+
__export(wizard_exports, {
|
|
2860
|
+
runWizard: () => runWizard
|
|
2861
|
+
});
|
|
2862
|
+
import { intro as intro2, select as select4, spinner as spinner6, note as note7, outro as outro6, isCancel as isCancel7 } from "@clack/prompts";
|
|
2863
|
+
import pc8 from "picocolors";
|
|
2864
|
+
import * as fs16 from "fs";
|
|
2670
2865
|
async function runWizard() {
|
|
2671
2866
|
intro2(pc8.cyan(pc8.inverse(" RRCE-Workflow Setup ")));
|
|
2672
2867
|
const s = spinner6();
|
|
@@ -2686,18 +2881,18 @@ Workspace: ${pc8.bold(workspaceName)}`,
|
|
|
2686
2881
|
workspacePath
|
|
2687
2882
|
});
|
|
2688
2883
|
const configFilePath = getConfigPath(workspacePath);
|
|
2689
|
-
const isAlreadyConfigured =
|
|
2884
|
+
const isAlreadyConfigured = fs16.existsSync(configFilePath);
|
|
2690
2885
|
let currentStorageMode = null;
|
|
2691
2886
|
if (isAlreadyConfigured) {
|
|
2692
2887
|
try {
|
|
2693
|
-
const configContent =
|
|
2888
|
+
const configContent = fs16.readFileSync(configFilePath, "utf-8");
|
|
2694
2889
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
2695
2890
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
2696
2891
|
} catch {
|
|
2697
2892
|
}
|
|
2698
2893
|
}
|
|
2699
2894
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
2700
|
-
const hasLocalData =
|
|
2895
|
+
const hasLocalData = fs16.existsSync(localDataPath);
|
|
2701
2896
|
if (isAlreadyConfigured) {
|
|
2702
2897
|
const menuOptions = [];
|
|
2703
2898
|
menuOptions.push({
|
|
@@ -2748,6 +2943,22 @@ Workspace: ${pc8.bold(workspaceName)}`,
|
|
|
2748
2943
|
}
|
|
2749
2944
|
await runSetupFlow(workspacePath, workspaceName, detectedProjects);
|
|
2750
2945
|
}
|
|
2946
|
+
var init_wizard = __esm({
|
|
2947
|
+
"src/commands/wizard/index.ts"() {
|
|
2948
|
+
"use strict";
|
|
2949
|
+
init_git();
|
|
2950
|
+
init_paths();
|
|
2951
|
+
init_detection();
|
|
2952
|
+
init_setup_flow();
|
|
2953
|
+
init_link_flow();
|
|
2954
|
+
init_sync_flow();
|
|
2955
|
+
init_update_flow();
|
|
2956
|
+
init_mcp();
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2959
|
+
|
|
2960
|
+
// src/index.ts
|
|
2961
|
+
init_wizard();
|
|
2751
2962
|
|
|
2752
2963
|
// src/commands/selector.ts
|
|
2753
2964
|
init_prompts();
|
|
@@ -2767,9 +2978,14 @@ async function runSelector() {
|
|
|
2767
2978
|
options: [
|
|
2768
2979
|
{
|
|
2769
2980
|
value: "mcp",
|
|
2770
|
-
label: "Manage MCP Hub",
|
|
2981
|
+
label: "\u{1F50C} Manage MCP Hub",
|
|
2771
2982
|
hint: "Configure & Start MCP Server"
|
|
2772
2983
|
},
|
|
2984
|
+
{
|
|
2985
|
+
value: "wizard",
|
|
2986
|
+
label: "\u2728 Run Setup Wizard",
|
|
2987
|
+
hint: "Configure workspace & agents"
|
|
2988
|
+
},
|
|
2773
2989
|
...prompts.map((p) => ({
|
|
2774
2990
|
value: p,
|
|
2775
2991
|
label: p.frontmatter.name,
|
|
@@ -2786,6 +3002,11 @@ async function runSelector() {
|
|
|
2786
3002
|
await runMCP2();
|
|
2787
3003
|
return;
|
|
2788
3004
|
}
|
|
3005
|
+
if (selection === "wizard") {
|
|
3006
|
+
const { runWizard: runWizard2 } = await Promise.resolve().then(() => (init_wizard(), wizard_exports));
|
|
3007
|
+
await runWizard2();
|
|
3008
|
+
return;
|
|
3009
|
+
}
|
|
2789
3010
|
const prompt = selection;
|
|
2790
3011
|
note8(
|
|
2791
3012
|
`Use this agent in your IDE by invoking:
|