rrce-workflow 0.2.27 → 0.2.29
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 +779 -445
- package/package.json +1 -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,20 @@ var init_types = __esm({
|
|
|
583
721
|
});
|
|
584
722
|
|
|
585
723
|
// src/mcp/config.ts
|
|
586
|
-
import * as
|
|
587
|
-
import * as
|
|
724
|
+
import * as fs7 from "fs";
|
|
725
|
+
import * as path8 from "path";
|
|
588
726
|
function getMCPConfigPath() {
|
|
589
727
|
const workspaceRoot = detectWorkspaceRoot();
|
|
590
728
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
591
|
-
return
|
|
729
|
+
return path8.join(rrceHome, "mcp.yaml");
|
|
592
730
|
}
|
|
593
731
|
function ensureMCPGlobalPath() {
|
|
594
732
|
const workspaceRoot = detectWorkspaceRoot();
|
|
595
733
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
596
734
|
if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
|
|
597
|
-
const configPath =
|
|
598
|
-
if (
|
|
599
|
-
const content =
|
|
735
|
+
const configPath = path8.join(workspaceRoot, ".rrce-workflow", "config.yaml");
|
|
736
|
+
if (fs7.existsSync(configPath)) {
|
|
737
|
+
const content = fs7.readFileSync(configPath, "utf-8");
|
|
600
738
|
const modeMatch = content.match(/mode:\s*(global|workspace)/);
|
|
601
739
|
if (modeMatch?.[1] === "workspace") {
|
|
602
740
|
return {
|
|
@@ -614,11 +752,11 @@ function ensureMCPGlobalPath() {
|
|
|
614
752
|
}
|
|
615
753
|
function loadMCPConfig() {
|
|
616
754
|
const configPath = getMCPConfigPath();
|
|
617
|
-
if (!
|
|
755
|
+
if (!fs7.existsSync(configPath)) {
|
|
618
756
|
return { ...DEFAULT_MCP_CONFIG };
|
|
619
757
|
}
|
|
620
758
|
try {
|
|
621
|
-
const content =
|
|
759
|
+
const content = fs7.readFileSync(configPath, "utf-8");
|
|
622
760
|
return parseMCPConfig(content);
|
|
623
761
|
} catch {
|
|
624
762
|
return { ...DEFAULT_MCP_CONFIG };
|
|
@@ -626,12 +764,12 @@ function loadMCPConfig() {
|
|
|
626
764
|
}
|
|
627
765
|
function saveMCPConfig(config) {
|
|
628
766
|
const configPath = getMCPConfigPath();
|
|
629
|
-
const dir =
|
|
630
|
-
if (!
|
|
631
|
-
|
|
767
|
+
const dir = path8.dirname(configPath);
|
|
768
|
+
if (!fs7.existsSync(dir)) {
|
|
769
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
632
770
|
}
|
|
633
771
|
const content = serializeMCPConfig(config);
|
|
634
|
-
|
|
772
|
+
fs7.writeFileSync(configPath, content);
|
|
635
773
|
}
|
|
636
774
|
function parseMCPConfig(content) {
|
|
637
775
|
const config = { ...DEFAULT_MCP_CONFIG, projects: [] };
|
|
@@ -794,12 +932,12 @@ __export(logger_exports, {
|
|
|
794
932
|
getLogFilePath: () => getLogFilePath,
|
|
795
933
|
logger: () => logger
|
|
796
934
|
});
|
|
797
|
-
import * as
|
|
798
|
-
import * as
|
|
935
|
+
import * as fs8 from "fs";
|
|
936
|
+
import * as path9 from "path";
|
|
799
937
|
function getLogFilePath() {
|
|
800
938
|
const workspaceRoot = detectWorkspaceRoot();
|
|
801
939
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
802
|
-
return
|
|
940
|
+
return path9.join(rrceHome, "mcp-server.log");
|
|
803
941
|
}
|
|
804
942
|
var Logger, logger;
|
|
805
943
|
var init_logger = __esm({
|
|
@@ -830,11 +968,11 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
830
968
|
}
|
|
831
969
|
logMessage += "\n";
|
|
832
970
|
try {
|
|
833
|
-
const dir =
|
|
834
|
-
if (!
|
|
835
|
-
|
|
971
|
+
const dir = path9.dirname(this.logPath);
|
|
972
|
+
if (!fs8.existsSync(dir)) {
|
|
973
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
836
974
|
}
|
|
837
|
-
|
|
975
|
+
fs8.appendFileSync(this.logPath, logMessage);
|
|
838
976
|
} catch (e) {
|
|
839
977
|
console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
|
|
840
978
|
console.error(logMessage);
|
|
@@ -858,8 +996,8 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
858
996
|
});
|
|
859
997
|
|
|
860
998
|
// src/mcp/resources.ts
|
|
861
|
-
import * as
|
|
862
|
-
import * as
|
|
999
|
+
import * as fs9 from "fs";
|
|
1000
|
+
import * as path10 from "path";
|
|
863
1001
|
function getExposedProjects() {
|
|
864
1002
|
const config = loadMCPConfig();
|
|
865
1003
|
const allProjects = scanForProjects();
|
|
@@ -886,11 +1024,11 @@ function getProjectContext(projectName) {
|
|
|
886
1024
|
if (!project?.knowledgePath) {
|
|
887
1025
|
return null;
|
|
888
1026
|
}
|
|
889
|
-
const contextPath =
|
|
890
|
-
if (!
|
|
1027
|
+
const contextPath = path10.join(project.knowledgePath, "project-context.md");
|
|
1028
|
+
if (!fs9.existsSync(contextPath)) {
|
|
891
1029
|
return null;
|
|
892
1030
|
}
|
|
893
|
-
return
|
|
1031
|
+
return fs9.readFileSync(contextPath, "utf-8");
|
|
894
1032
|
}
|
|
895
1033
|
function getProjectTasks(projectName) {
|
|
896
1034
|
const config = loadMCPConfig();
|
|
@@ -903,18 +1041,18 @@ function getProjectTasks(projectName) {
|
|
|
903
1041
|
}
|
|
904
1042
|
const projects = scanForProjects();
|
|
905
1043
|
const project = projects.find((p) => p.name === projectName);
|
|
906
|
-
if (!project?.tasksPath || !
|
|
1044
|
+
if (!project?.tasksPath || !fs9.existsSync(project.tasksPath)) {
|
|
907
1045
|
return [];
|
|
908
1046
|
}
|
|
909
1047
|
const tasks = [];
|
|
910
1048
|
try {
|
|
911
|
-
const taskDirs =
|
|
1049
|
+
const taskDirs = fs9.readdirSync(project.tasksPath, { withFileTypes: true });
|
|
912
1050
|
for (const dir of taskDirs) {
|
|
913
1051
|
if (!dir.isDirectory()) continue;
|
|
914
|
-
const metaPath =
|
|
915
|
-
if (
|
|
1052
|
+
const metaPath = path10.join(project.tasksPath, dir.name, "meta.json");
|
|
1053
|
+
if (fs9.existsSync(metaPath)) {
|
|
916
1054
|
try {
|
|
917
|
-
const meta = JSON.parse(
|
|
1055
|
+
const meta = JSON.parse(fs9.readFileSync(metaPath, "utf-8"));
|
|
918
1056
|
tasks.push(meta);
|
|
919
1057
|
} catch {
|
|
920
1058
|
}
|
|
@@ -933,11 +1071,11 @@ function searchKnowledge(query) {
|
|
|
933
1071
|
const permissions = getProjectPermissions(config, project.name);
|
|
934
1072
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
935
1073
|
try {
|
|
936
|
-
const files =
|
|
1074
|
+
const files = fs9.readdirSync(project.knowledgePath);
|
|
937
1075
|
for (const file of files) {
|
|
938
1076
|
if (!file.endsWith(".md")) continue;
|
|
939
|
-
const filePath =
|
|
940
|
-
const content =
|
|
1077
|
+
const filePath = path10.join(project.knowledgePath, file);
|
|
1078
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
941
1079
|
const lines = content.split("\n");
|
|
942
1080
|
const matches = [];
|
|
943
1081
|
for (const line of lines) {
|
|
@@ -1105,8 +1243,9 @@ function registerResourceHandlers(server) {
|
|
|
1105
1243
|
};
|
|
1106
1244
|
}
|
|
1107
1245
|
const projectMatch = uri.match(/^rrce:\/\/projects\/([^/]+)\/(.+)$/);
|
|
1108
|
-
if (projectMatch) {
|
|
1109
|
-
const
|
|
1246
|
+
if (projectMatch && projectMatch[1] && projectMatch[2]) {
|
|
1247
|
+
const projectName = projectMatch[1];
|
|
1248
|
+
const resourceType = projectMatch[2];
|
|
1110
1249
|
const content = resourceType === "context" ? getProjectContext(projectName) : JSON.stringify(getProjectTasks(projectName), null, 2);
|
|
1111
1250
|
if (content === null) throw new Error(`Resource not found: ${uri}`);
|
|
1112
1251
|
return {
|
|
@@ -1357,34 +1496,81 @@ var init_server = __esm({
|
|
|
1357
1496
|
});
|
|
1358
1497
|
|
|
1359
1498
|
// src/mcp/install.ts
|
|
1360
|
-
import * as
|
|
1361
|
-
import * as
|
|
1499
|
+
import * as fs10 from "fs";
|
|
1500
|
+
import * as path11 from "path";
|
|
1362
1501
|
import * as os from "os";
|
|
1363
|
-
function checkInstallStatus() {
|
|
1502
|
+
function checkInstallStatus(workspacePath) {
|
|
1364
1503
|
return {
|
|
1365
|
-
antigravity:
|
|
1366
|
-
claude:
|
|
1504
|
+
antigravity: checkAntigravityConfig(),
|
|
1505
|
+
claude: checkClaudeConfig(),
|
|
1506
|
+
vscodeGlobal: checkVSCodeGlobalConfig(),
|
|
1507
|
+
vscodeWorkspace: workspacePath ? checkVSCodeWorkspaceConfig(workspacePath) : false
|
|
1367
1508
|
};
|
|
1368
1509
|
}
|
|
1369
|
-
function
|
|
1370
|
-
if (!
|
|
1510
|
+
function checkAntigravityConfig() {
|
|
1511
|
+
if (!fs10.existsSync(ANTIGRAVITY_CONFIG)) return false;
|
|
1512
|
+
try {
|
|
1513
|
+
const content = JSON.parse(fs10.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
1514
|
+
return !!content.mcpServers?.["rrce"];
|
|
1515
|
+
} catch {
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
function checkClaudeConfig() {
|
|
1520
|
+
if (!fs10.existsSync(CLAUDE_CONFIG)) return false;
|
|
1371
1521
|
try {
|
|
1372
|
-
const content = JSON.parse(
|
|
1522
|
+
const content = JSON.parse(fs10.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
1373
1523
|
return !!content.mcpServers?.["rrce"];
|
|
1374
1524
|
} catch {
|
|
1375
1525
|
return false;
|
|
1376
1526
|
}
|
|
1377
1527
|
}
|
|
1378
|
-
function
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1528
|
+
function checkVSCodeGlobalConfig() {
|
|
1529
|
+
if (!fs10.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
|
|
1530
|
+
try {
|
|
1531
|
+
const content = JSON.parse(fs10.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
1532
|
+
return !!content["mcp.servers"]?.["rrce"];
|
|
1533
|
+
} catch {
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function checkVSCodeWorkspaceConfig(workspacePath) {
|
|
1538
|
+
const configPath = path11.join(workspacePath, ".vscode", "mcp.json");
|
|
1539
|
+
if (!fs10.existsSync(configPath)) return false;
|
|
1540
|
+
try {
|
|
1541
|
+
const content = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
|
|
1542
|
+
return !!content.servers?.["rrce"];
|
|
1543
|
+
} catch {
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
function isInstalledAnywhere(workspacePath) {
|
|
1548
|
+
const status = checkInstallStatus(workspacePath);
|
|
1549
|
+
return status.antigravity || status.claude || status.vscodeGlobal || status.vscodeWorkspace;
|
|
1550
|
+
}
|
|
1551
|
+
function installToConfig(target, workspacePath) {
|
|
1552
|
+
switch (target) {
|
|
1553
|
+
case "antigravity":
|
|
1554
|
+
return installToAntigravity();
|
|
1555
|
+
case "claude":
|
|
1556
|
+
return installToClaude();
|
|
1557
|
+
case "vscode-global":
|
|
1558
|
+
return installToVSCodeGlobal();
|
|
1559
|
+
case "vscode-workspace":
|
|
1560
|
+
return workspacePath ? installToVSCodeWorkspace(workspacePath) : false;
|
|
1561
|
+
default:
|
|
1562
|
+
return false;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
function installToAntigravity() {
|
|
1566
|
+
const dir = path11.dirname(ANTIGRAVITY_CONFIG);
|
|
1567
|
+
if (!fs10.existsSync(dir)) {
|
|
1568
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1383
1569
|
}
|
|
1384
1570
|
let config = { mcpServers: {} };
|
|
1385
|
-
if (
|
|
1571
|
+
if (fs10.existsSync(ANTIGRAVITY_CONFIG)) {
|
|
1386
1572
|
try {
|
|
1387
|
-
config = JSON.parse(
|
|
1573
|
+
config = JSON.parse(fs10.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
1388
1574
|
} catch {
|
|
1389
1575
|
}
|
|
1390
1576
|
}
|
|
@@ -1392,21 +1578,108 @@ function installToConfig(target) {
|
|
|
1392
1578
|
config.mcpServers["rrce"] = {
|
|
1393
1579
|
command: "npx",
|
|
1394
1580
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1395
|
-
// -y to avoid interactive prompts
|
|
1396
1581
|
};
|
|
1397
1582
|
try {
|
|
1398
|
-
|
|
1583
|
+
fs10.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
|
|
1584
|
+
return true;
|
|
1585
|
+
} catch {
|
|
1586
|
+
return false;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
function installToClaude() {
|
|
1590
|
+
const dir = path11.dirname(CLAUDE_CONFIG);
|
|
1591
|
+
if (!fs10.existsSync(dir)) {
|
|
1592
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1593
|
+
}
|
|
1594
|
+
let config = { mcpServers: {} };
|
|
1595
|
+
if (fs10.existsSync(CLAUDE_CONFIG)) {
|
|
1596
|
+
try {
|
|
1597
|
+
config = JSON.parse(fs10.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
1598
|
+
} catch {
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
1602
|
+
config.mcpServers["rrce"] = {
|
|
1603
|
+
command: "npx",
|
|
1604
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1605
|
+
};
|
|
1606
|
+
try {
|
|
1607
|
+
fs10.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
|
|
1608
|
+
return true;
|
|
1609
|
+
} catch {
|
|
1610
|
+
return false;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
function installToVSCodeGlobal() {
|
|
1614
|
+
const dir = path11.dirname(VSCODE_GLOBAL_CONFIG);
|
|
1615
|
+
if (!fs10.existsSync(dir)) {
|
|
1616
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1617
|
+
}
|
|
1618
|
+
let settings = {};
|
|
1619
|
+
if (fs10.existsSync(VSCODE_GLOBAL_CONFIG)) {
|
|
1620
|
+
try {
|
|
1621
|
+
settings = JSON.parse(fs10.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
1622
|
+
} catch {
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
if (!settings["mcp.servers"]) settings["mcp.servers"] = {};
|
|
1626
|
+
settings["mcp.servers"]["rrce"] = {
|
|
1627
|
+
command: "npx",
|
|
1628
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1629
|
+
};
|
|
1630
|
+
try {
|
|
1631
|
+
fs10.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
|
|
1632
|
+
return true;
|
|
1633
|
+
} catch {
|
|
1634
|
+
return false;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
function installToVSCodeWorkspace(workspacePath) {
|
|
1638
|
+
const vscodeDir = path11.join(workspacePath, ".vscode");
|
|
1639
|
+
const configPath = path11.join(vscodeDir, "mcp.json");
|
|
1640
|
+
if (!fs10.existsSync(vscodeDir)) {
|
|
1641
|
+
fs10.mkdirSync(vscodeDir, { recursive: true });
|
|
1642
|
+
}
|
|
1643
|
+
let config = { servers: {} };
|
|
1644
|
+
if (fs10.existsSync(configPath)) {
|
|
1645
|
+
try {
|
|
1646
|
+
config = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
|
|
1647
|
+
} catch {
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
if (!config.servers) config.servers = {};
|
|
1651
|
+
config.servers["rrce"] = {
|
|
1652
|
+
command: "npx",
|
|
1653
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1654
|
+
};
|
|
1655
|
+
try {
|
|
1656
|
+
fs10.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1399
1657
|
return true;
|
|
1400
1658
|
} catch {
|
|
1401
1659
|
return false;
|
|
1402
1660
|
}
|
|
1403
1661
|
}
|
|
1404
|
-
|
|
1662
|
+
function getTargetLabel(target) {
|
|
1663
|
+
switch (target) {
|
|
1664
|
+
case "antigravity":
|
|
1665
|
+
return "Antigravity IDE";
|
|
1666
|
+
case "claude":
|
|
1667
|
+
return "Claude Desktop";
|
|
1668
|
+
case "vscode-global":
|
|
1669
|
+
return "VSCode (Global)";
|
|
1670
|
+
case "vscode-workspace":
|
|
1671
|
+
return "VSCode (Workspace)";
|
|
1672
|
+
default:
|
|
1673
|
+
return target;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG;
|
|
1405
1677
|
var init_install = __esm({
|
|
1406
1678
|
"src/mcp/install.ts"() {
|
|
1407
1679
|
"use strict";
|
|
1408
|
-
ANTIGRAVITY_CONFIG =
|
|
1409
|
-
CLAUDE_CONFIG =
|
|
1680
|
+
ANTIGRAVITY_CONFIG = path11.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
|
|
1681
|
+
CLAUDE_CONFIG = path11.join(os.homedir(), ".config/claude/claude_desktop_config.json");
|
|
1682
|
+
VSCODE_GLOBAL_CONFIG = path11.join(os.homedir(), ".config/Code/User/settings.json");
|
|
1410
1683
|
}
|
|
1411
1684
|
});
|
|
1412
1685
|
|
|
@@ -1415,8 +1688,8 @@ var mcp_exports = {};
|
|
|
1415
1688
|
__export(mcp_exports, {
|
|
1416
1689
|
runMCP: () => runMCP
|
|
1417
1690
|
});
|
|
1418
|
-
import { intro
|
|
1419
|
-
import
|
|
1691
|
+
import { intro, outro, select as select2, multiselect, confirm, spinner, note as note2, cancel, isCancel as isCancel2, text } from "@clack/prompts";
|
|
1692
|
+
import pc3 from "picocolors";
|
|
1420
1693
|
async function runMCP(subcommand2) {
|
|
1421
1694
|
if (subcommand2) {
|
|
1422
1695
|
switch (subcommand2) {
|
|
@@ -1436,42 +1709,72 @@ async function runMCP(subcommand2) {
|
|
|
1436
1709
|
return;
|
|
1437
1710
|
}
|
|
1438
1711
|
}
|
|
1439
|
-
|
|
1712
|
+
intro(pc3.bgCyan(pc3.black(" RRCE MCP Hub ")));
|
|
1713
|
+
const workspacePath = detectWorkspaceRoot();
|
|
1440
1714
|
const globalPathCheck = await ensureMCPGlobalPath();
|
|
1441
1715
|
if (!globalPathCheck.configured) {
|
|
1442
1716
|
const configured = await handleConfigureGlobalPath();
|
|
1443
1717
|
if (!configured) {
|
|
1444
|
-
|
|
1718
|
+
outro(pc3.yellow("MCP requires a global storage path. Setup cancelled."));
|
|
1445
1719
|
return;
|
|
1446
1720
|
}
|
|
1447
1721
|
}
|
|
1448
|
-
const
|
|
1449
|
-
if (!
|
|
1450
|
-
|
|
1451
|
-
|
|
1722
|
+
const installed = isInstalledAnywhere(workspacePath);
|
|
1723
|
+
if (!installed) {
|
|
1724
|
+
note2(
|
|
1725
|
+
`${pc3.bold("Welcome to RRCE MCP Hub!")}
|
|
1726
|
+
|
|
1727
|
+
MCP (Model Context Protocol) allows AI assistants to access your
|
|
1728
|
+
project knowledge in real-time. Let's get you set up.`,
|
|
1729
|
+
"Getting Started"
|
|
1730
|
+
);
|
|
1731
|
+
const shouldInstall = await confirm({
|
|
1732
|
+
message: "Install MCP server to your IDE(s)?",
|
|
1452
1733
|
initialValue: true
|
|
1453
1734
|
});
|
|
1454
|
-
if (shouldInstall && !
|
|
1455
|
-
await handleInstallWizard();
|
|
1735
|
+
if (shouldInstall && !isCancel2(shouldInstall)) {
|
|
1736
|
+
await handleInstallWizard(workspacePath);
|
|
1737
|
+
const config2 = loadMCPConfig();
|
|
1738
|
+
const exposedCount2 = config2.projects.filter((p) => p.expose).length;
|
|
1739
|
+
if (exposedCount2 === 0) {
|
|
1740
|
+
await handleConfigure();
|
|
1741
|
+
}
|
|
1742
|
+
const shouldStart = await confirm({
|
|
1743
|
+
message: "Start the MCP server now?",
|
|
1744
|
+
initialValue: true
|
|
1745
|
+
});
|
|
1746
|
+
if (shouldStart && !isCancel2(shouldStart)) {
|
|
1747
|
+
await handleStartServer();
|
|
1748
|
+
}
|
|
1456
1749
|
}
|
|
1750
|
+
outro(pc3.green("MCP Hub setup complete!"));
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
const config = loadMCPConfig();
|
|
1754
|
+
const exposedCount = config.projects.filter((p) => p.expose).length;
|
|
1755
|
+
if (exposedCount === 0 && !config.defaults.includeNew) {
|
|
1756
|
+
note2("MCP is installed but no projects are exposed. Let's configure that.", "Configuration Needed");
|
|
1757
|
+
await handleConfigure();
|
|
1457
1758
|
}
|
|
1458
1759
|
let running = true;
|
|
1459
1760
|
while (running) {
|
|
1460
1761
|
const serverStatus = getMCPServerStatus();
|
|
1461
|
-
const serverLabel = serverStatus.running ?
|
|
1462
|
-
const
|
|
1762
|
+
const serverLabel = serverStatus.running ? pc3.green("\u25CF Running") : pc3.dim("\u25CB Stopped");
|
|
1763
|
+
const currentStatus = checkInstallStatus(workspacePath);
|
|
1764
|
+
const installedCount = [currentStatus.antigravity, currentStatus.claude, currentStatus.vscodeGlobal, currentStatus.vscodeWorkspace].filter(Boolean).length;
|
|
1765
|
+
const action = await select2({
|
|
1463
1766
|
message: "What would you like to do?",
|
|
1464
1767
|
options: [
|
|
1465
|
-
{ value: "start", label: `\u25B6\uFE0F Start MCP server`, hint:
|
|
1768
|
+
{ value: "start", label: `\u25B6\uFE0F Start MCP server`, hint: serverLabel },
|
|
1466
1769
|
{ value: "configure", label: "\u2699\uFE0F Configure projects", hint: "Choose which projects to expose" },
|
|
1467
|
-
{ value: "install", label: "\u{1F4E5} Install to IDE", hint:
|
|
1770
|
+
{ value: "install", label: "\u{1F4E5} Install to IDE", hint: `${installedCount} IDE(s) configured` },
|
|
1468
1771
|
{ value: "status", label: "\u{1F4CB} View status", hint: "See details" },
|
|
1469
1772
|
{ value: "help", label: "\u2753 Help", hint: "Learn about MCP Hub" },
|
|
1470
1773
|
{ value: "exit", label: "\u21A9 Exit", hint: "Return to shell" }
|
|
1471
1774
|
]
|
|
1472
1775
|
});
|
|
1473
|
-
if (
|
|
1474
|
-
|
|
1776
|
+
if (isCancel2(action)) {
|
|
1777
|
+
cancel("MCP Hub closed.");
|
|
1475
1778
|
return;
|
|
1476
1779
|
}
|
|
1477
1780
|
switch (action) {
|
|
@@ -1482,7 +1785,7 @@ async function runMCP(subcommand2) {
|
|
|
1482
1785
|
await handleConfigure();
|
|
1483
1786
|
break;
|
|
1484
1787
|
case "install":
|
|
1485
|
-
await handleInstallWizard();
|
|
1788
|
+
await handleInstallWizard(workspacePath);
|
|
1486
1789
|
break;
|
|
1487
1790
|
case "status":
|
|
1488
1791
|
await handleShowStatus();
|
|
@@ -1495,140 +1798,227 @@ async function runMCP(subcommand2) {
|
|
|
1495
1798
|
break;
|
|
1496
1799
|
}
|
|
1497
1800
|
}
|
|
1498
|
-
|
|
1801
|
+
outro(pc3.green("MCP Hub closed."));
|
|
1499
1802
|
}
|
|
1500
|
-
async function handleInstallWizard() {
|
|
1501
|
-
const status = checkInstallStatus();
|
|
1803
|
+
async function handleInstallWizard(workspacePath) {
|
|
1804
|
+
const status = checkInstallStatus(workspacePath);
|
|
1502
1805
|
const options = [
|
|
1503
|
-
{
|
|
1504
|
-
|
|
1806
|
+
{
|
|
1807
|
+
value: "antigravity",
|
|
1808
|
+
label: "Antigravity IDE",
|
|
1809
|
+
hint: status.antigravity ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
value: "vscode-global",
|
|
1813
|
+
label: "VSCode (Global Settings)",
|
|
1814
|
+
hint: status.vscodeGlobal ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1815
|
+
},
|
|
1816
|
+
{
|
|
1817
|
+
value: "vscode-workspace",
|
|
1818
|
+
label: "VSCode (Workspace Config)",
|
|
1819
|
+
hint: status.vscodeWorkspace ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
value: "claude",
|
|
1823
|
+
label: "Claude Desktop",
|
|
1824
|
+
hint: status.claude ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")
|
|
1825
|
+
}
|
|
1505
1826
|
];
|
|
1506
|
-
const selected = await
|
|
1827
|
+
const selected = await multiselect({
|
|
1507
1828
|
message: "Select where to install RRCE MCP Server:",
|
|
1508
1829
|
options,
|
|
1509
1830
|
initialValues: [
|
|
1510
1831
|
...status.antigravity ? ["antigravity"] : [],
|
|
1832
|
+
...status.vscodeGlobal ? ["vscode-global"] : [],
|
|
1833
|
+
...status.vscodeWorkspace ? ["vscode-workspace"] : [],
|
|
1511
1834
|
...status.claude ? ["claude"] : []
|
|
1512
1835
|
],
|
|
1513
1836
|
required: false
|
|
1514
1837
|
});
|
|
1515
|
-
if (
|
|
1838
|
+
if (isCancel2(selected)) return;
|
|
1516
1839
|
const targets = selected;
|
|
1517
1840
|
const results = [];
|
|
1518
1841
|
for (const target of targets) {
|
|
1519
|
-
const success = installToConfig(target);
|
|
1520
|
-
|
|
1842
|
+
const success = installToConfig(target, workspacePath);
|
|
1843
|
+
const label = getTargetLabel(target);
|
|
1844
|
+
results.push(`${label}: ${success ? pc3.green("\u2713 Success") : pc3.red("\u2717 Failed")}`);
|
|
1521
1845
|
}
|
|
1522
1846
|
if (results.length > 0) {
|
|
1523
|
-
|
|
1847
|
+
note2(results.join("\n"), "Installation Results");
|
|
1524
1848
|
}
|
|
1525
1849
|
}
|
|
1526
1850
|
async function handleStartServer() {
|
|
1527
1851
|
const fs16 = await import("fs");
|
|
1528
1852
|
const { getLogFilePath: getLogFilePath2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
1529
1853
|
const config = loadMCPConfig();
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1532
|
-
const
|
|
1854
|
+
const projects = scanForProjects();
|
|
1855
|
+
const exposedProjects = projects.filter((p) => {
|
|
1856
|
+
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1857
|
+
return cfg?.expose ?? config.defaults.includeNew;
|
|
1858
|
+
});
|
|
1859
|
+
if (exposedProjects.length === 0) {
|
|
1860
|
+
const shouldConfig = await confirm({
|
|
1533
1861
|
message: "No projects are currently exposed. Configure now?",
|
|
1534
1862
|
initialValue: true
|
|
1535
1863
|
});
|
|
1536
|
-
if (shouldConfig && !
|
|
1864
|
+
if (shouldConfig && !isCancel2(shouldConfig)) {
|
|
1537
1865
|
await handleConfigure();
|
|
1866
|
+
return handleStartServer();
|
|
1538
1867
|
}
|
|
1539
1868
|
}
|
|
1540
|
-
const
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1869
|
+
const status = getMCPServerStatus();
|
|
1870
|
+
let newPort = config.server.port;
|
|
1871
|
+
if (!status.running) {
|
|
1872
|
+
const portInput = await text({
|
|
1873
|
+
message: "Select port for MCP Server",
|
|
1874
|
+
initialValue: config.server.port.toString(),
|
|
1875
|
+
placeholder: "3200",
|
|
1876
|
+
validate(value) {
|
|
1877
|
+
if (isNaN(Number(value))) return "Port must be a number";
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
if (isCancel2(portInput)) return;
|
|
1881
|
+
newPort = parseInt(portInput, 10);
|
|
1882
|
+
if (newPort !== config.server.port) {
|
|
1883
|
+
config.server.port = newPort;
|
|
1884
|
+
saveMCPConfig(config);
|
|
1546
1885
|
}
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
if (newPort !== config.server.port) {
|
|
1551
|
-
config.server.port = newPort;
|
|
1552
|
-
saveMCPConfig(config);
|
|
1886
|
+
} else {
|
|
1887
|
+
newPort = status.port || newPort;
|
|
1888
|
+
note2(`Server is already running on port ${newPort}`, "Info");
|
|
1553
1889
|
}
|
|
1554
1890
|
console.clear();
|
|
1555
1891
|
const logPath = getLogFilePath2();
|
|
1556
|
-
const
|
|
1892
|
+
const exposedNames = exposedProjects.map((p) => p.name).slice(0, 5);
|
|
1893
|
+
const exposedLabel = exposedNames.length > 0 ? exposedNames.join(", ") + (exposedProjects.length > 5 ? ` (+${exposedProjects.length - 5} more)` : "") : pc3.dim("(none)");
|
|
1894
|
+
const render = (logs = []) => {
|
|
1557
1895
|
console.clear();
|
|
1558
|
-
console.log(
|
|
1559
|
-
console.log(
|
|
1560
|
-
console.log(
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1896
|
+
console.log(pc3.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"));
|
|
1897
|
+
console.log(pc3.cyan("\u2551") + pc3.bold(pc3.white(" RRCE MCP Hub Running ")) + pc3.cyan("\u2551"));
|
|
1898
|
+
console.log(pc3.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"));
|
|
1899
|
+
const logLines = logs.slice(-10);
|
|
1900
|
+
const emptyLines = 10 - logLines.length;
|
|
1901
|
+
for (let i = 0; i < emptyLines; i++) {
|
|
1902
|
+
console.log(pc3.cyan("\u2551") + " ".repeat(63) + pc3.cyan("\u2551"));
|
|
1903
|
+
}
|
|
1904
|
+
for (const line of logLines) {
|
|
1905
|
+
const cleanLine = line.replace(/\u001b\[\d+m/g, "");
|
|
1906
|
+
const truncated = cleanLine.substring(0, 61).padEnd(61);
|
|
1907
|
+
console.log(pc3.cyan("\u2551") + " " + pc3.dim(truncated) + " " + pc3.cyan("\u2551"));
|
|
1908
|
+
}
|
|
1909
|
+
console.log(pc3.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"));
|
|
1910
|
+
const infoLine = ` \u{1F4CB} ${exposedLabel} \u2502 Port: ${newPort} \u2502 PID: ${process.pid || "?"}`.substring(0, 61).padEnd(61);
|
|
1911
|
+
console.log(pc3.cyan("\u2551") + pc3.yellow(infoLine) + " " + pc3.cyan("\u2551"));
|
|
1912
|
+
console.log(pc3.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"));
|
|
1913
|
+
const cmdLine = ` q:Quit p:Projects i:Install r:Reload c:Clear ?:Help`;
|
|
1914
|
+
console.log(pc3.cyan("\u2551") + pc3.dim(cmdLine.padEnd(63)) + pc3.cyan("\u2551"));
|
|
1915
|
+
console.log(pc3.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"));
|
|
1570
1916
|
};
|
|
1571
|
-
|
|
1572
|
-
|
|
1917
|
+
let logBuffer = [];
|
|
1918
|
+
render(logBuffer);
|
|
1573
1919
|
try {
|
|
1574
|
-
|
|
1920
|
+
if (!status.running) {
|
|
1921
|
+
await startMCPServer();
|
|
1922
|
+
}
|
|
1575
1923
|
let lastSize = 0;
|
|
1576
1924
|
if (fs16.existsSync(logPath)) {
|
|
1577
1925
|
const stats = fs16.statSync(logPath);
|
|
1578
1926
|
lastSize = stats.size;
|
|
1579
1927
|
}
|
|
1580
1928
|
let isRunning = true;
|
|
1929
|
+
let interval;
|
|
1581
1930
|
if (process.stdin.setRawMode) {
|
|
1582
1931
|
process.stdin.setRawMode(true);
|
|
1583
1932
|
process.stdin.resume();
|
|
1584
1933
|
process.stdin.setEncoding("utf8");
|
|
1585
1934
|
}
|
|
1586
1935
|
return new Promise((resolve) => {
|
|
1936
|
+
const cleanup = (shouldStopServer) => {
|
|
1937
|
+
isRunning = false;
|
|
1938
|
+
clearInterval(interval);
|
|
1939
|
+
if (process.stdin.setRawMode) {
|
|
1940
|
+
process.stdin.setRawMode(false);
|
|
1941
|
+
}
|
|
1942
|
+
process.stdin.removeListener("data", onKey);
|
|
1943
|
+
process.stdin.pause();
|
|
1944
|
+
if (shouldStopServer) {
|
|
1945
|
+
stopMCPServer();
|
|
1946
|
+
}
|
|
1947
|
+
console.log("");
|
|
1948
|
+
};
|
|
1587
1949
|
const onKey = async (key) => {
|
|
1588
1950
|
if (key === "" || key.toLowerCase() === "q") {
|
|
1589
|
-
cleanup();
|
|
1951
|
+
cleanup(true);
|
|
1952
|
+
resolve();
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
if (key.toLowerCase() === "p") {
|
|
1956
|
+
cleanup(false);
|
|
1957
|
+
console.clear();
|
|
1958
|
+
await handleConfigure();
|
|
1959
|
+
await handleStartServer();
|
|
1590
1960
|
resolve();
|
|
1961
|
+
return;
|
|
1591
1962
|
}
|
|
1592
|
-
if (key.toLowerCase() === "
|
|
1593
|
-
cleanup();
|
|
1963
|
+
if (key.toLowerCase() === "i") {
|
|
1964
|
+
cleanup(false);
|
|
1965
|
+
console.clear();
|
|
1966
|
+
await handleInstallWizard(detectWorkspaceRoot());
|
|
1967
|
+
await handleStartServer();
|
|
1594
1968
|
resolve();
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
if (key.toLowerCase() === "r") {
|
|
1972
|
+
logBuffer.push("[INFO] Reloading configuration...");
|
|
1973
|
+
render(logBuffer);
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
if (key.toLowerCase() === "c") {
|
|
1977
|
+
logBuffer = [];
|
|
1978
|
+
render(logBuffer);
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
if (key === "?") {
|
|
1982
|
+
logBuffer.push("\u2500".repeat(40));
|
|
1983
|
+
logBuffer.push("Commands:");
|
|
1984
|
+
logBuffer.push(" q - Stop server and return to menu");
|
|
1985
|
+
logBuffer.push(" p - Reconfigure exposed projects");
|
|
1986
|
+
logBuffer.push(" i - Install to additional IDEs");
|
|
1987
|
+
logBuffer.push(" r - Reload configuration");
|
|
1988
|
+
logBuffer.push(" c - Clear log display");
|
|
1989
|
+
logBuffer.push(" ? - Show this help");
|
|
1990
|
+
logBuffer.push("\u2500".repeat(40));
|
|
1991
|
+
render(logBuffer);
|
|
1992
|
+
return;
|
|
1595
1993
|
}
|
|
1596
1994
|
};
|
|
1597
1995
|
process.stdin.on("data", onKey);
|
|
1598
|
-
|
|
1996
|
+
interval = setInterval(() => {
|
|
1599
1997
|
if (!isRunning) return;
|
|
1600
1998
|
if (fs16.existsSync(logPath)) {
|
|
1601
1999
|
const stats = fs16.statSync(logPath);
|
|
1602
2000
|
if (stats.size > lastSize) {
|
|
1603
|
-
const
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
2001
|
+
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
2002
|
+
const fd = fs16.openSync(logPath, "r");
|
|
2003
|
+
fs16.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
2004
|
+
fs16.closeSync(fd);
|
|
2005
|
+
const newContent = buffer.toString("utf-8");
|
|
2006
|
+
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
2007
|
+
logBuffer.push(...newLines);
|
|
2008
|
+
if (logBuffer.length > 100) {
|
|
2009
|
+
logBuffer = logBuffer.slice(-100);
|
|
2010
|
+
}
|
|
1611
2011
|
lastSize = stats.size;
|
|
2012
|
+
render(logBuffer);
|
|
1612
2013
|
}
|
|
1613
2014
|
}
|
|
1614
2015
|
}, 500);
|
|
1615
|
-
const cleanup = () => {
|
|
1616
|
-
isRunning = false;
|
|
1617
|
-
clearInterval(interval);
|
|
1618
|
-
if (process.stdin.setRawMode) {
|
|
1619
|
-
process.stdin.setRawMode(false);
|
|
1620
|
-
}
|
|
1621
|
-
process.stdin.removeListener("data", onKey);
|
|
1622
|
-
process.stdin.pause();
|
|
1623
|
-
stopMCPServer();
|
|
1624
|
-
console.log("");
|
|
1625
|
-
};
|
|
1626
2016
|
});
|
|
1627
2017
|
} catch (error) {
|
|
1628
2018
|
if (process.stdin.setRawMode) {
|
|
1629
2019
|
process.stdin.setRawMode(false);
|
|
1630
2020
|
}
|
|
1631
|
-
console.error(
|
|
2021
|
+
console.error(pc3.red("\nFailed to start/monitor server:"));
|
|
1632
2022
|
console.error(error);
|
|
1633
2023
|
}
|
|
1634
2024
|
}
|
|
@@ -1636,11 +2026,11 @@ async function handleConfigureGlobalPath() {
|
|
|
1636
2026
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
1637
2027
|
const fs16 = await import("fs");
|
|
1638
2028
|
const path16 = await import("path");
|
|
1639
|
-
|
|
1640
|
-
`MCP Hub requires a ${
|
|
2029
|
+
note2(
|
|
2030
|
+
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
1641
2031
|
and coordinate across projects.
|
|
1642
2032
|
|
|
1643
|
-
Your current setup uses ${
|
|
2033
|
+
Your current setup uses ${pc3.cyan("workspace")} mode, which stores data
|
|
1644
2034
|
locally in each project. MCP needs a central location.`,
|
|
1645
2035
|
"Global Path Required"
|
|
1646
2036
|
);
|
|
@@ -1654,8 +2044,8 @@ locally in each project. MCP needs a central location.`,
|
|
|
1654
2044
|
}
|
|
1655
2045
|
const config = loadMCPConfig();
|
|
1656
2046
|
saveMCPConfig(config);
|
|
1657
|
-
|
|
1658
|
-
`${
|
|
2047
|
+
note2(
|
|
2048
|
+
`${pc3.green("\u2713")} Global path configured: ${pc3.cyan(resolvedPath)}
|
|
1659
2049
|
|
|
1660
2050
|
MCP config will be stored at:
|
|
1661
2051
|
${path16.join(resolvedPath, "mcp.yaml")}`,
|
|
@@ -1663,54 +2053,63 @@ ${path16.join(resolvedPath, "mcp.yaml")}`,
|
|
|
1663
2053
|
);
|
|
1664
2054
|
return true;
|
|
1665
2055
|
} catch (error) {
|
|
1666
|
-
|
|
1667
|
-
`${
|
|
2056
|
+
note2(
|
|
2057
|
+
`${pc3.red("\u2717")} Failed to create directory: ${error instanceof Error ? error.message : String(error)}`,
|
|
1668
2058
|
"Error"
|
|
1669
2059
|
);
|
|
1670
2060
|
return false;
|
|
1671
2061
|
}
|
|
1672
2062
|
}
|
|
1673
2063
|
async function handleShowStatus() {
|
|
1674
|
-
const s =
|
|
2064
|
+
const s = spinner();
|
|
1675
2065
|
s.start("Loading projects...");
|
|
1676
2066
|
const config = loadMCPConfig();
|
|
1677
2067
|
const projects = scanForProjects();
|
|
2068
|
+
const workspacePath = detectWorkspaceRoot();
|
|
2069
|
+
const installStatus = checkInstallStatus(workspacePath);
|
|
1678
2070
|
s.stop("Projects loaded");
|
|
1679
2071
|
if (projects.length === 0) {
|
|
1680
|
-
|
|
2072
|
+
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
1681
2073
|
return;
|
|
1682
2074
|
}
|
|
1683
2075
|
const lines = [
|
|
1684
|
-
`${
|
|
2076
|
+
`${pc3.bold("Installation Status")}`,
|
|
2077
|
+
"",
|
|
2078
|
+
` Antigravity: ${installStatus.antigravity ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2079
|
+
` VSCode (Global): ${installStatus.vscodeGlobal ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2080
|
+
` VSCode (Workspace): ${installStatus.vscodeWorkspace ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2081
|
+
` Claude Desktop: ${installStatus.claude ? pc3.green("\u2713 Installed") : pc3.dim("Not installed")}`,
|
|
2082
|
+
"",
|
|
2083
|
+
`${pc3.bold("Project Status")}`,
|
|
1685
2084
|
""
|
|
1686
2085
|
];
|
|
1687
2086
|
for (const project of projects) {
|
|
1688
2087
|
const projectConfig = config.projects.find((p) => p.name === project.name);
|
|
1689
2088
|
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
1690
|
-
const status = isExposed ?
|
|
1691
|
-
const source =
|
|
2089
|
+
const status = isExposed ? pc3.green("\u2713 exposed") : pc3.dim("\u25CB hidden");
|
|
2090
|
+
const source = pc3.dim(`(${project.source})`);
|
|
1692
2091
|
lines.push(` ${status} ${project.name} ${source}`);
|
|
1693
2092
|
}
|
|
1694
2093
|
lines.push("");
|
|
1695
|
-
lines.push(
|
|
2094
|
+
lines.push(pc3.dim(`Config: ${getMCPConfigPath()}`));
|
|
1696
2095
|
const serverStatus = getMCPServerStatus();
|
|
1697
2096
|
if (serverStatus.running) {
|
|
1698
|
-
lines.push(
|
|
2097
|
+
lines.push(pc3.green(`Server: running on port ${serverStatus.port}`));
|
|
1699
2098
|
} else {
|
|
1700
|
-
lines.push(
|
|
2099
|
+
lines.push(pc3.dim("Server: not running"));
|
|
1701
2100
|
}
|
|
1702
|
-
|
|
2101
|
+
note2(lines.join("\n"), "MCP Hub Status");
|
|
1703
2102
|
}
|
|
1704
2103
|
async function handleConfigure() {
|
|
1705
2104
|
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
1706
|
-
const s =
|
|
2105
|
+
const s = spinner();
|
|
1707
2106
|
s.start("Scanning for projects...");
|
|
1708
2107
|
const config = loadMCPConfig();
|
|
1709
2108
|
const projects = scanForProjects();
|
|
1710
2109
|
logger2.info("Configure: Loaded config", { projects: config.projects, defaultMode: config.defaults.includeNew });
|
|
1711
2110
|
s.stop("Projects found");
|
|
1712
2111
|
if (projects.length === 0) {
|
|
1713
|
-
|
|
2112
|
+
note2('No RRCE projects detected. Run "rrce-workflow" in a project to set it up.', "No Projects");
|
|
1714
2113
|
return;
|
|
1715
2114
|
}
|
|
1716
2115
|
const options = projects.map((project) => {
|
|
@@ -1718,7 +2117,7 @@ async function handleConfigure() {
|
|
|
1718
2117
|
const isExposed = projectConfig?.expose ?? config.defaults.includeNew;
|
|
1719
2118
|
return {
|
|
1720
2119
|
value: project.name,
|
|
1721
|
-
label: `${project.name} ${
|
|
2120
|
+
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
1722
2121
|
hint: project.dataPath
|
|
1723
2122
|
};
|
|
1724
2123
|
});
|
|
@@ -1726,13 +2125,13 @@ async function handleConfigure() {
|
|
|
1726
2125
|
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1727
2126
|
return cfg?.expose ?? config.defaults.includeNew;
|
|
1728
2127
|
}).map((p) => p.name);
|
|
1729
|
-
const selected = await
|
|
2128
|
+
const selected = await multiselect({
|
|
1730
2129
|
message: "Select projects to expose via MCP:",
|
|
1731
2130
|
options,
|
|
1732
2131
|
initialValues: currentlyExposed,
|
|
1733
2132
|
required: false
|
|
1734
2133
|
});
|
|
1735
|
-
if (
|
|
2134
|
+
if (isCancel2(selected)) {
|
|
1736
2135
|
return;
|
|
1737
2136
|
}
|
|
1738
2137
|
const selectedNames = selected;
|
|
@@ -1744,8 +2143,8 @@ async function handleConfigure() {
|
|
|
1744
2143
|
saveMCPConfig(config);
|
|
1745
2144
|
logger2.info("Configure: Config saved", config);
|
|
1746
2145
|
const exposedCount = selectedNames.length;
|
|
1747
|
-
|
|
1748
|
-
`${
|
|
2146
|
+
note2(
|
|
2147
|
+
`${pc3.green("\u2713")} Configuration saved!
|
|
1749
2148
|
|
|
1750
2149
|
Exposed projects: ${exposedCount}
|
|
1751
2150
|
Hidden projects: ${projects.length - exposedCount}`,
|
|
@@ -1755,65 +2154,57 @@ Hidden projects: ${projects.length - exposedCount}`,
|
|
|
1755
2154
|
async function handleStopServer() {
|
|
1756
2155
|
const status = getMCPServerStatus();
|
|
1757
2156
|
if (!status.running) {
|
|
1758
|
-
|
|
2157
|
+
note2("MCP server is not running.", "Status");
|
|
1759
2158
|
return;
|
|
1760
2159
|
}
|
|
1761
|
-
const confirmed = await
|
|
2160
|
+
const confirmed = await confirm({
|
|
1762
2161
|
message: "Stop the MCP server?",
|
|
1763
2162
|
initialValue: true
|
|
1764
2163
|
});
|
|
1765
|
-
if (
|
|
2164
|
+
if (isCancel2(confirmed) || !confirmed) {
|
|
1766
2165
|
return;
|
|
1767
2166
|
}
|
|
1768
2167
|
stopMCPServer();
|
|
1769
|
-
|
|
2168
|
+
note2(pc3.green("MCP server stopped."), "Server Stopped");
|
|
1770
2169
|
}
|
|
1771
2170
|
function showHelp() {
|
|
1772
2171
|
const help = `
|
|
1773
|
-
${
|
|
2172
|
+
${pc3.bold("RRCE MCP Hub")} - Cross-project AI assistant server
|
|
1774
2173
|
|
|
1775
|
-
${
|
|
2174
|
+
${pc3.bold("ABOUT")}
|
|
1776
2175
|
MCP (Model Context Protocol) allows AI assistants like Claude to
|
|
1777
2176
|
access your project knowledge in real-time. The RRCE MCP Hub
|
|
1778
2177
|
provides a central server that exposes selected projects.
|
|
1779
2178
|
|
|
1780
|
-
${
|
|
1781
|
-
${
|
|
1782
|
-
${
|
|
1783
|
-
${
|
|
1784
|
-
${
|
|
2179
|
+
${pc3.bold("MENU OPTIONS")}
|
|
2180
|
+
${pc3.cyan("Start MCP server")} Start the server for AI access
|
|
2181
|
+
${pc3.cyan("Configure projects")} Choose which projects to expose
|
|
2182
|
+
${pc3.cyan("Install to IDE")} Add to Antigravity, VSCode, or Claude
|
|
2183
|
+
${pc3.cyan("View status")} See which projects are exposed
|
|
1785
2184
|
|
|
1786
|
-
${
|
|
1787
|
-
${
|
|
1788
|
-
${
|
|
1789
|
-
${
|
|
1790
|
-
${
|
|
2185
|
+
${pc3.bold("DIRECT COMMANDS")}
|
|
2186
|
+
${pc3.dim("rrce-workflow mcp start")} Start server directly
|
|
2187
|
+
${pc3.dim("rrce-workflow mcp stop")} Stop server directly
|
|
2188
|
+
${pc3.dim("rrce-workflow mcp status")} Show status directly
|
|
2189
|
+
${pc3.dim("rrce-workflow mcp help")} Show this help
|
|
1791
2190
|
|
|
1792
|
-
${
|
|
1793
|
-
|
|
1794
|
-
${
|
|
1795
|
-
"
|
|
1796
|
-
|
|
1797
|
-
"command": "npx",
|
|
1798
|
-
"args": ["rrce-workflow", "mcp", "start"]
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
}`)}
|
|
2191
|
+
${pc3.bold("IDE INSTALLATION")}
|
|
2192
|
+
${pc3.cyan("Antigravity")} ~/.gemini/antigravity/mcp_config.json
|
|
2193
|
+
${pc3.cyan("VSCode Global")} ~/.config/Code/User/settings.json
|
|
2194
|
+
${pc3.cyan("VSCode Workspace")} .vscode/mcp.json
|
|
2195
|
+
${pc3.cyan("Claude Desktop")} ~/.config/claude/claude_desktop_config.json
|
|
1802
2196
|
|
|
1803
|
-
${
|
|
1804
|
-
${
|
|
1805
|
-
${
|
|
1806
|
-
${
|
|
2197
|
+
${pc3.bold("SERVER COMMANDS")} (while running)
|
|
2198
|
+
${pc3.cyan("q")} Stop and quit ${pc3.cyan("p")} Reconfigure projects
|
|
2199
|
+
${pc3.cyan("i")} Install to IDE ${pc3.cyan("r")} Reload config
|
|
2200
|
+
${pc3.cyan("c")} Clear logs ${pc3.cyan("?")} Show help
|
|
1807
2201
|
|
|
1808
|
-
${
|
|
1809
|
-
${
|
|
1810
|
-
${
|
|
1811
|
-
${
|
|
1812
|
-
${pc8.cyan("execute")} Implement planned work
|
|
1813
|
-
${pc8.cyan("docs")} Generate documentation
|
|
1814
|
-
${pc8.cyan("sync")} Sync knowledge with codebase
|
|
2202
|
+
${pc3.bold("RESOURCES EXPOSED")}
|
|
2203
|
+
${pc3.cyan("rrce://projects")} List all exposed projects
|
|
2204
|
+
${pc3.cyan("rrce://projects/{name}/context")} Get project context
|
|
2205
|
+
${pc3.cyan("rrce://projects/{name}/tasks")} Get project tasks
|
|
1815
2206
|
`;
|
|
1816
|
-
|
|
2207
|
+
note2(help.trim(), "Help");
|
|
1817
2208
|
}
|
|
1818
2209
|
var init_mcp = __esm({
|
|
1819
2210
|
"src/mcp/index.ts"() {
|
|
@@ -1822,157 +2213,20 @@ var init_mcp = __esm({
|
|
|
1822
2213
|
init_detection();
|
|
1823
2214
|
init_server();
|
|
1824
2215
|
init_install();
|
|
2216
|
+
init_paths();
|
|
1825
2217
|
}
|
|
1826
2218
|
});
|
|
1827
2219
|
|
|
1828
|
-
// src/commands/wizard/index.ts
|
|
1829
|
-
import { intro, select as select3, spinner as spinner5, note as note6, outro as outro5, isCancel as isCancel6 } from "@clack/prompts";
|
|
1830
|
-
import pc7 from "picocolors";
|
|
1831
|
-
import * as fs11 from "fs";
|
|
1832
|
-
|
|
1833
|
-
// src/lib/git.ts
|
|
1834
|
-
import { execSync } from "child_process";
|
|
1835
|
-
function getGitUser() {
|
|
1836
|
-
try {
|
|
1837
|
-
const result = execSync("git config user.name", { encoding: "utf-8" });
|
|
1838
|
-
return result.trim() || null;
|
|
1839
|
-
} catch {
|
|
1840
|
-
return null;
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
// src/commands/wizard/index.ts
|
|
1845
|
-
init_paths();
|
|
1846
|
-
init_detection();
|
|
1847
|
-
|
|
1848
2220
|
// src/commands/wizard/setup-flow.ts
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
import
|
|
1852
|
-
import
|
|
1853
|
-
import * as fs7 from "fs";
|
|
1854
|
-
import * as path8 from "path";
|
|
1855
|
-
|
|
1856
|
-
// src/commands/wizard/utils.ts
|
|
1857
|
-
init_paths();
|
|
1858
|
-
import * as fs4 from "fs";
|
|
1859
|
-
import * as path4 from "path";
|
|
1860
|
-
function copyPromptsToDir(prompts, targetDir, extension) {
|
|
1861
|
-
for (const prompt of prompts) {
|
|
1862
|
-
const baseName = path4.basename(prompt.filePath, ".md");
|
|
1863
|
-
const targetName = baseName + extension;
|
|
1864
|
-
const targetPath = path4.join(targetDir, targetName);
|
|
1865
|
-
const content = fs4.readFileSync(prompt.filePath, "utf-8");
|
|
1866
|
-
fs4.writeFileSync(targetPath, content);
|
|
1867
|
-
}
|
|
1868
|
-
}
|
|
1869
|
-
function copyDirRecursive(src, dest) {
|
|
1870
|
-
const entries = fs4.readdirSync(src, { withFileTypes: true });
|
|
1871
|
-
for (const entry of entries) {
|
|
1872
|
-
const srcPath = path4.join(src, entry.name);
|
|
1873
|
-
const destPath = path4.join(dest, entry.name);
|
|
1874
|
-
if (entry.isDirectory()) {
|
|
1875
|
-
ensureDir(destPath);
|
|
1876
|
-
copyDirRecursive(srcPath, destPath);
|
|
1877
|
-
} else {
|
|
1878
|
-
fs4.copyFileSync(srcPath, destPath);
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
|
-
// src/commands/wizard/vscode.ts
|
|
1884
|
-
init_paths();
|
|
1885
|
-
init_detection();
|
|
1886
|
-
import * as fs5 from "fs";
|
|
1887
|
-
import * as path5 from "path";
|
|
1888
|
-
function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
1889
|
-
const workspaceFilePath = path5.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
1890
|
-
let workspace;
|
|
1891
|
-
if (fs5.existsSync(workspaceFilePath)) {
|
|
1892
|
-
try {
|
|
1893
|
-
const content = fs5.readFileSync(workspaceFilePath, "utf-8");
|
|
1894
|
-
workspace = JSON.parse(content);
|
|
1895
|
-
} catch {
|
|
1896
|
-
workspace = { folders: [], settings: {} };
|
|
1897
|
-
}
|
|
1898
|
-
} else {
|
|
1899
|
-
workspace = { folders: [], settings: {} };
|
|
1900
|
-
}
|
|
1901
|
-
if (!workspace.settings) {
|
|
1902
|
-
workspace.settings = {};
|
|
1903
|
-
}
|
|
1904
|
-
workspace.folders = workspace.folders.filter(
|
|
1905
|
-
(f) => f.path === "." || !f.name?.startsWith("\u{1F4C1}") && !f.name?.startsWith("\u{1F4DA}") && !f.name?.startsWith("\u{1F4CE}") && !f.name?.startsWith("\u{1F4CB}")
|
|
1906
|
-
);
|
|
1907
|
-
const mainFolderIndex = workspace.folders.findIndex((f) => f.path === ".");
|
|
1908
|
-
if (mainFolderIndex === -1) {
|
|
1909
|
-
workspace.folders.unshift({
|
|
1910
|
-
path: ".",
|
|
1911
|
-
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
1912
|
-
});
|
|
1913
|
-
} else {
|
|
1914
|
-
workspace.folders[mainFolderIndex] = {
|
|
1915
|
-
path: ".",
|
|
1916
|
-
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
1917
|
-
};
|
|
1918
|
-
}
|
|
1919
|
-
const referenceFolderPaths = [];
|
|
1920
|
-
const isDetectedProjects = linkedProjects.length > 0 && typeof linkedProjects[0] === "object";
|
|
1921
|
-
if (isDetectedProjects) {
|
|
1922
|
-
const projects = linkedProjects;
|
|
1923
|
-
for (const project of projects) {
|
|
1924
|
-
const sourceLabel = project.source === "global" ? "global" : "local";
|
|
1925
|
-
const folderPath = project.dataPath;
|
|
1926
|
-
if (fs5.existsSync(folderPath)) {
|
|
1927
|
-
referenceFolderPaths.push(folderPath);
|
|
1928
|
-
workspace.folders.push({
|
|
1929
|
-
path: folderPath,
|
|
1930
|
-
name: `\u{1F4C1} ${project.name} [${sourceLabel}]`
|
|
1931
|
-
});
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
} else {
|
|
1935
|
-
const projectNames = linkedProjects;
|
|
1936
|
-
const rrceHome = customGlobalPath || getRRCEHome();
|
|
1937
|
-
for (const projectName of projectNames) {
|
|
1938
|
-
const folderPath = path5.join(rrceHome, "workspaces", projectName);
|
|
1939
|
-
if (fs5.existsSync(folderPath)) {
|
|
1940
|
-
referenceFolderPaths.push(folderPath);
|
|
1941
|
-
workspace.folders.push({
|
|
1942
|
-
path: folderPath,
|
|
1943
|
-
name: `\u{1F4C1} ${projectName} [global]`
|
|
1944
|
-
});
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
if (referenceFolderPaths.length > 0) {
|
|
1949
|
-
const readonlyPatterns = {};
|
|
1950
|
-
for (const folderPath of referenceFolderPaths) {
|
|
1951
|
-
readonlyPatterns[`${folderPath}/**`] = true;
|
|
1952
|
-
}
|
|
1953
|
-
const existingReadonly = workspace.settings["files.readonlyInclude"] || {};
|
|
1954
|
-
const cleanedReadonly = {};
|
|
1955
|
-
for (const [pattern, value] of Object.entries(existingReadonly)) {
|
|
1956
|
-
if (!pattern.includes(".rrce-workflow") && !pattern.includes("rrce-workflow/workspaces")) {
|
|
1957
|
-
cleanedReadonly[pattern] = value;
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
workspace.settings["files.readonlyInclude"] = {
|
|
1961
|
-
...cleanedReadonly,
|
|
1962
|
-
...readonlyPatterns
|
|
1963
|
-
};
|
|
1964
|
-
}
|
|
1965
|
-
fs5.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
1966
|
-
}
|
|
1967
|
-
|
|
1968
|
-
// src/commands/wizard/setup-flow.ts
|
|
1969
|
-
init_detection();
|
|
1970
|
-
init_tui_utils();
|
|
2221
|
+
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";
|
|
2222
|
+
import pc4 from "picocolors";
|
|
2223
|
+
import * as fs11 from "fs";
|
|
2224
|
+
import * as path12 from "path";
|
|
1971
2225
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
1972
|
-
const s =
|
|
2226
|
+
const s = spinner2();
|
|
1973
2227
|
const config = await group(
|
|
1974
2228
|
{
|
|
1975
|
-
storageMode: () =>
|
|
2229
|
+
storageMode: () => select3({
|
|
1976
2230
|
message: "Where should workflow data be stored?",
|
|
1977
2231
|
options: [
|
|
1978
2232
|
{ value: "global", label: "Global (~/.rrce-workflow/)", hint: "Cross-project access, clean workspace" },
|
|
@@ -1980,7 +2234,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
1980
2234
|
],
|
|
1981
2235
|
initialValue: "global"
|
|
1982
2236
|
}),
|
|
1983
|
-
tools: () =>
|
|
2237
|
+
tools: () => multiselect2({
|
|
1984
2238
|
message: "Which AI tools do you use?",
|
|
1985
2239
|
options: [
|
|
1986
2240
|
{ value: "copilot", label: "GitHub Copilot", hint: "VSCode" },
|
|
@@ -1992,44 +2246,44 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
1992
2246
|
if (existingProjects.length === 0) {
|
|
1993
2247
|
return Promise.resolve([]);
|
|
1994
2248
|
}
|
|
1995
|
-
return
|
|
2249
|
+
return multiselect2({
|
|
1996
2250
|
message: "Link knowledge from other projects?",
|
|
1997
2251
|
options: existingProjects.map((project) => ({
|
|
1998
2252
|
value: `${project.name}:${project.source}`,
|
|
1999
2253
|
// Unique key
|
|
2000
|
-
label: `${project.name} ${
|
|
2001
|
-
hint:
|
|
2254
|
+
label: `${project.name} ${pc4.dim(`(${project.source})`)}`,
|
|
2255
|
+
hint: pc4.dim(
|
|
2002
2256
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
2003
2257
|
)
|
|
2004
2258
|
})),
|
|
2005
2259
|
required: false
|
|
2006
2260
|
});
|
|
2007
2261
|
},
|
|
2008
|
-
addToGitignore: () =>
|
|
2262
|
+
addToGitignore: () => confirm2({
|
|
2009
2263
|
message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
|
|
2010
2264
|
initialValue: true
|
|
2011
2265
|
}),
|
|
2012
|
-
confirm: () =>
|
|
2266
|
+
confirm: () => confirm2({
|
|
2013
2267
|
message: "Create configuration?",
|
|
2014
2268
|
initialValue: true
|
|
2015
2269
|
})
|
|
2016
2270
|
},
|
|
2017
2271
|
{
|
|
2018
2272
|
onCancel: () => {
|
|
2019
|
-
|
|
2273
|
+
cancel2("Setup process cancelled.");
|
|
2020
2274
|
process.exit(0);
|
|
2021
2275
|
}
|
|
2022
2276
|
}
|
|
2023
2277
|
);
|
|
2024
2278
|
if (!config.confirm) {
|
|
2025
|
-
|
|
2279
|
+
outro2("Setup cancelled by user.");
|
|
2026
2280
|
process.exit(0);
|
|
2027
2281
|
}
|
|
2028
2282
|
let customGlobalPath;
|
|
2029
2283
|
if (config.storageMode === "global") {
|
|
2030
2284
|
customGlobalPath = await resolveGlobalPath();
|
|
2031
2285
|
if (!customGlobalPath) {
|
|
2032
|
-
|
|
2286
|
+
cancel2("Setup cancelled - no writable global path available.");
|
|
2033
2287
|
process.exit(1);
|
|
2034
2288
|
}
|
|
2035
2289
|
}
|
|
@@ -2053,7 +2307,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2053
2307
|
`Storage: ${config.storageMode}`
|
|
2054
2308
|
];
|
|
2055
2309
|
if (customGlobalPath && customGlobalPath !== getDefaultRRCEHome()) {
|
|
2056
|
-
summary.push(`Global path: ${
|
|
2310
|
+
summary.push(`Global path: ${pc4.cyan(customGlobalPath)}`);
|
|
2057
2311
|
}
|
|
2058
2312
|
if (dataPaths.length > 0) {
|
|
2059
2313
|
summary.push(`Data paths:`);
|
|
@@ -2066,17 +2320,26 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2066
2320
|
const linkedProjects = config.linkedProjects;
|
|
2067
2321
|
if (linkedProjects.length > 0) {
|
|
2068
2322
|
summary.push(`Linked projects: ${linkedProjects.join(", ")}`);
|
|
2069
|
-
summary.push(`Workspace file: ${
|
|
2323
|
+
summary.push(`Workspace file: ${pc4.cyan(`${workspaceName}.code-workspace`)}`);
|
|
2070
2324
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2325
|
+
note3(summary.join("\n"), "Setup Summary");
|
|
2326
|
+
const shouldConfigureMCP = await confirm2({
|
|
2327
|
+
message: "Would you like to configure the MCP server now?",
|
|
2328
|
+
initialValue: true
|
|
2329
|
+
});
|
|
2330
|
+
if (shouldConfigureMCP && !isCancel3(shouldConfigureMCP)) {
|
|
2331
|
+
const { runMCP: runMCP2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
2332
|
+
await runMCP2();
|
|
2074
2333
|
} else {
|
|
2075
|
-
|
|
2334
|
+
if (linkedProjects.length > 0) {
|
|
2335
|
+
outro2(pc4.green(`\u2713 Setup complete! Open ${pc4.bold(`${workspaceName}.code-workspace`)} in VSCode to access linked knowledge.`));
|
|
2336
|
+
} else {
|
|
2337
|
+
outro2(pc4.green(`\u2713 Setup complete! Your agents are ready to use.`));
|
|
2338
|
+
}
|
|
2076
2339
|
}
|
|
2077
2340
|
} catch (error) {
|
|
2078
2341
|
s.stop("Error occurred");
|
|
2079
|
-
|
|
2342
|
+
cancel2(`Failed to setup: ${error instanceof Error ? error.message : String(error)}`);
|
|
2080
2343
|
process.exit(1);
|
|
2081
2344
|
}
|
|
2082
2345
|
}
|
|
@@ -2084,14 +2347,14 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
2084
2347
|
const dataPaths = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
|
|
2085
2348
|
for (const dataPath of dataPaths) {
|
|
2086
2349
|
ensureDir(dataPath);
|
|
2087
|
-
ensureDir(
|
|
2088
|
-
ensureDir(
|
|
2089
|
-
ensureDir(
|
|
2090
|
-
ensureDir(
|
|
2350
|
+
ensureDir(path12.join(dataPath, "knowledge"));
|
|
2351
|
+
ensureDir(path12.join(dataPath, "refs"));
|
|
2352
|
+
ensureDir(path12.join(dataPath, "tasks"));
|
|
2353
|
+
ensureDir(path12.join(dataPath, "templates"));
|
|
2091
2354
|
}
|
|
2092
2355
|
const agentCoreDir = getAgentCoreDir();
|
|
2093
2356
|
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
2094
|
-
copyDirToAllStoragePaths(
|
|
2357
|
+
copyDirToAllStoragePaths(path12.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
2095
2358
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
2096
2359
|
if (config.tools.includes("copilot")) {
|
|
2097
2360
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
@@ -2103,8 +2366,8 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
2103
2366
|
ensureDir(antigravityPath);
|
|
2104
2367
|
copyPromptsToDir(prompts, antigravityPath, ".md");
|
|
2105
2368
|
}
|
|
2106
|
-
const workspaceConfigPath =
|
|
2107
|
-
ensureDir(
|
|
2369
|
+
const workspaceConfigPath = path12.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
2370
|
+
ensureDir(path12.dirname(workspaceConfigPath));
|
|
2108
2371
|
let configContent = `# RRCE-Workflow Configuration
|
|
2109
2372
|
version: 1
|
|
2110
2373
|
|
|
@@ -2132,7 +2395,7 @@ linked_projects:
|
|
|
2132
2395
|
`;
|
|
2133
2396
|
});
|
|
2134
2397
|
}
|
|
2135
|
-
|
|
2398
|
+
fs11.writeFileSync(workspaceConfigPath, configContent);
|
|
2136
2399
|
if (config.addToGitignore) {
|
|
2137
2400
|
updateGitignore(workspacePath, config.storageMode, config.tools);
|
|
2138
2401
|
}
|
|
@@ -2144,8 +2407,8 @@ linked_projects:
|
|
|
2144
2407
|
}
|
|
2145
2408
|
}
|
|
2146
2409
|
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
2147
|
-
const globalPath =
|
|
2148
|
-
const workspacePath =
|
|
2410
|
+
const globalPath = path12.join(customGlobalPath || getDefaultRRCEHome(), "workspaces", workspaceName);
|
|
2411
|
+
const workspacePath = path12.join(workspaceRoot, ".rrce-workflow");
|
|
2149
2412
|
switch (mode) {
|
|
2150
2413
|
case "global":
|
|
2151
2414
|
return [globalPath];
|
|
@@ -2156,7 +2419,7 @@ function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
|
2156
2419
|
}
|
|
2157
2420
|
}
|
|
2158
2421
|
function updateGitignore(workspacePath, storageMode, tools) {
|
|
2159
|
-
const gitignorePath =
|
|
2422
|
+
const gitignorePath = path12.join(workspacePath, ".gitignore");
|
|
2160
2423
|
const entries = [];
|
|
2161
2424
|
if (storageMode === "workspace") {
|
|
2162
2425
|
entries.push(".rrce-workflow/");
|
|
@@ -2172,8 +2435,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2172
2435
|
}
|
|
2173
2436
|
try {
|
|
2174
2437
|
let content = "";
|
|
2175
|
-
if (
|
|
2176
|
-
content =
|
|
2438
|
+
if (fs11.existsSync(gitignorePath)) {
|
|
2439
|
+
content = fs11.readFileSync(gitignorePath, "utf-8");
|
|
2177
2440
|
}
|
|
2178
2441
|
const lines = content.split("\n").map((line) => line.trim());
|
|
2179
2442
|
const newEntries = [];
|
|
@@ -2198,57 +2461,66 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2198
2461
|
newContent += "\n# rrce-workflow generated folders (uncomment to ignore)\n";
|
|
2199
2462
|
}
|
|
2200
2463
|
newContent += newEntries.map((e) => `# ${e}`).join("\n") + "\n";
|
|
2201
|
-
|
|
2464
|
+
fs11.writeFileSync(gitignorePath, newContent);
|
|
2202
2465
|
return true;
|
|
2203
2466
|
} catch {
|
|
2204
2467
|
return false;
|
|
2205
2468
|
}
|
|
2206
2469
|
}
|
|
2470
|
+
var init_setup_flow = __esm({
|
|
2471
|
+
"src/commands/wizard/setup-flow.ts"() {
|
|
2472
|
+
"use strict";
|
|
2473
|
+
init_paths();
|
|
2474
|
+
init_prompts();
|
|
2475
|
+
init_utils();
|
|
2476
|
+
init_vscode();
|
|
2477
|
+
init_detection();
|
|
2478
|
+
init_tui_utils();
|
|
2479
|
+
}
|
|
2480
|
+
});
|
|
2207
2481
|
|
|
2208
2482
|
// src/commands/wizard/link-flow.ts
|
|
2209
|
-
|
|
2210
|
-
import
|
|
2211
|
-
import
|
|
2212
|
-
import * as fs8 from "fs";
|
|
2213
|
-
init_detection();
|
|
2483
|
+
import { multiselect as multiselect3, spinner as spinner3, note as note4, outro as outro3, cancel as cancel3, isCancel as isCancel4 } from "@clack/prompts";
|
|
2484
|
+
import pc5 from "picocolors";
|
|
2485
|
+
import * as fs12 from "fs";
|
|
2214
2486
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
2215
2487
|
const projects = scanForProjects({
|
|
2216
2488
|
excludeWorkspace: workspaceName,
|
|
2217
2489
|
workspacePath
|
|
2218
2490
|
});
|
|
2219
2491
|
if (projects.length === 0) {
|
|
2220
|
-
|
|
2492
|
+
outro3(pc5.yellow("No other projects found. Try setting up another project first."));
|
|
2221
2493
|
return;
|
|
2222
2494
|
}
|
|
2223
2495
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2224
|
-
const linkedProjects = await
|
|
2496
|
+
const linkedProjects = await multiselect3({
|
|
2225
2497
|
message: "Select projects to link:",
|
|
2226
2498
|
options: projects.map((project) => ({
|
|
2227
2499
|
value: `${project.name}:${project.source}`,
|
|
2228
2500
|
// Unique key
|
|
2229
|
-
label: `${project.name} ${
|
|
2230
|
-
hint:
|
|
2501
|
+
label: `${project.name} ${pc5.dim(`(${project.source})`)}`,
|
|
2502
|
+
hint: pc5.dim(
|
|
2231
2503
|
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
2232
2504
|
)
|
|
2233
2505
|
})),
|
|
2234
2506
|
required: true
|
|
2235
2507
|
});
|
|
2236
|
-
if (
|
|
2237
|
-
|
|
2508
|
+
if (isCancel4(linkedProjects)) {
|
|
2509
|
+
cancel3("Cancelled.");
|
|
2238
2510
|
process.exit(0);
|
|
2239
2511
|
}
|
|
2240
2512
|
const selectedKeys = linkedProjects;
|
|
2241
2513
|
if (selectedKeys.length === 0) {
|
|
2242
|
-
|
|
2514
|
+
outro3("No projects selected.");
|
|
2243
2515
|
return;
|
|
2244
2516
|
}
|
|
2245
2517
|
const selectedProjects = projects.filter(
|
|
2246
2518
|
(p) => selectedKeys.includes(`${p.name}:${p.source}`)
|
|
2247
2519
|
);
|
|
2248
|
-
const s =
|
|
2520
|
+
const s = spinner3();
|
|
2249
2521
|
s.start("Linking projects");
|
|
2250
2522
|
const configFilePath = getConfigPath(workspacePath);
|
|
2251
|
-
let configContent =
|
|
2523
|
+
let configContent = fs12.readFileSync(configFilePath, "utf-8");
|
|
2252
2524
|
if (configContent.includes("linked_projects:")) {
|
|
2253
2525
|
const lines = configContent.split("\n");
|
|
2254
2526
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -2275,60 +2547,67 @@ linked_projects:
|
|
|
2275
2547
|
`;
|
|
2276
2548
|
});
|
|
2277
2549
|
}
|
|
2278
|
-
|
|
2550
|
+
fs12.writeFileSync(configFilePath, configContent);
|
|
2279
2551
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
2280
2552
|
s.stop("Projects linked");
|
|
2281
2553
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
2282
2554
|
const summary = [
|
|
2283
2555
|
`Linked projects:`,
|
|
2284
|
-
...selectedProjects.map((p) => ` \u2713 ${p.name} ${
|
|
2556
|
+
...selectedProjects.map((p) => ` \u2713 ${p.name} ${pc5.dim(`(${p.source})`)}`),
|
|
2285
2557
|
``,
|
|
2286
|
-
`Workspace file: ${
|
|
2558
|
+
`Workspace file: ${pc5.cyan(workspaceFile)}`
|
|
2287
2559
|
];
|
|
2288
|
-
|
|
2289
|
-
|
|
2560
|
+
note4(summary.join("\n"), "Link Summary");
|
|
2561
|
+
outro3(pc5.green(`\u2713 Projects linked! Open ${pc5.bold(workspaceFile)} in VSCode to access linked data.`));
|
|
2290
2562
|
}
|
|
2563
|
+
var init_link_flow = __esm({
|
|
2564
|
+
"src/commands/wizard/link-flow.ts"() {
|
|
2565
|
+
"use strict";
|
|
2566
|
+
init_paths();
|
|
2567
|
+
init_vscode();
|
|
2568
|
+
init_detection();
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2291
2571
|
|
|
2292
2572
|
// src/commands/wizard/sync-flow.ts
|
|
2293
|
-
|
|
2294
|
-
import
|
|
2295
|
-
import
|
|
2296
|
-
import * as
|
|
2297
|
-
import * as path9 from "path";
|
|
2573
|
+
import { confirm as confirm3, spinner as spinner4, note as note5, outro as outro4, cancel as cancel4, isCancel as isCancel5 } from "@clack/prompts";
|
|
2574
|
+
import pc6 from "picocolors";
|
|
2575
|
+
import * as fs13 from "fs";
|
|
2576
|
+
import * as path13 from "path";
|
|
2298
2577
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
2299
2578
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
2300
2579
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2301
|
-
const globalPath =
|
|
2580
|
+
const globalPath = path13.join(customGlobalPath, "workspaces", workspaceName);
|
|
2302
2581
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
2303
2582
|
const existingDirs = subdirs.filter(
|
|
2304
|
-
(dir) =>
|
|
2583
|
+
(dir) => fs13.existsSync(path13.join(localPath, dir))
|
|
2305
2584
|
);
|
|
2306
2585
|
if (existingDirs.length === 0) {
|
|
2307
|
-
|
|
2586
|
+
outro4(pc6.yellow("No data found in workspace storage to sync."));
|
|
2308
2587
|
return;
|
|
2309
2588
|
}
|
|
2310
|
-
|
|
2589
|
+
note5(
|
|
2311
2590
|
`The following will be copied to global storage:
|
|
2312
2591
|
${existingDirs.map((d) => ` \u2022 ${d}/`).join("\n")}
|
|
2313
2592
|
|
|
2314
|
-
Destination: ${
|
|
2593
|
+
Destination: ${pc6.cyan(globalPath)}`,
|
|
2315
2594
|
"Sync Preview"
|
|
2316
2595
|
);
|
|
2317
|
-
const shouldSync = await
|
|
2596
|
+
const shouldSync = await confirm3({
|
|
2318
2597
|
message: "Proceed with sync to global storage?",
|
|
2319
2598
|
initialValue: true
|
|
2320
2599
|
});
|
|
2321
|
-
if (
|
|
2322
|
-
|
|
2600
|
+
if (isCancel5(shouldSync) || !shouldSync) {
|
|
2601
|
+
outro4("Sync cancelled.");
|
|
2323
2602
|
return;
|
|
2324
2603
|
}
|
|
2325
|
-
const s =
|
|
2604
|
+
const s = spinner4();
|
|
2326
2605
|
s.start("Syncing to global storage");
|
|
2327
2606
|
try {
|
|
2328
2607
|
ensureDir(globalPath);
|
|
2329
2608
|
for (const dir of existingDirs) {
|
|
2330
|
-
const srcDir =
|
|
2331
|
-
const destDir =
|
|
2609
|
+
const srcDir = path13.join(localPath, dir);
|
|
2610
|
+
const destDir = path13.join(globalPath, dir);
|
|
2332
2611
|
ensureDir(destDir);
|
|
2333
2612
|
copyDirRecursive(srcDir, destDir);
|
|
2334
2613
|
}
|
|
@@ -2337,28 +2616,33 @@ Destination: ${pc5.cyan(globalPath)}`,
|
|
|
2337
2616
|
`Synced directories:`,
|
|
2338
2617
|
...existingDirs.map((d) => ` \u2713 ${d}/`),
|
|
2339
2618
|
``,
|
|
2340
|
-
`Global path: ${
|
|
2619
|
+
`Global path: ${pc6.cyan(globalPath)}`,
|
|
2341
2620
|
``,
|
|
2342
2621
|
`Other projects can now link this knowledge!`
|
|
2343
2622
|
];
|
|
2344
|
-
|
|
2345
|
-
|
|
2623
|
+
note5(summary.join("\n"), "Sync Summary");
|
|
2624
|
+
outro4(pc6.green("\u2713 Workspace knowledge synced to global storage!"));
|
|
2346
2625
|
} catch (error) {
|
|
2347
2626
|
s.stop("Error occurred");
|
|
2348
|
-
|
|
2627
|
+
cancel4(`Failed to sync: ${error instanceof Error ? error.message : String(error)}`);
|
|
2349
2628
|
process.exit(1);
|
|
2350
2629
|
}
|
|
2351
2630
|
}
|
|
2631
|
+
var init_sync_flow = __esm({
|
|
2632
|
+
"src/commands/wizard/sync-flow.ts"() {
|
|
2633
|
+
"use strict";
|
|
2634
|
+
init_paths();
|
|
2635
|
+
init_utils();
|
|
2636
|
+
}
|
|
2637
|
+
});
|
|
2352
2638
|
|
|
2353
2639
|
// src/commands/wizard/update-flow.ts
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
import
|
|
2357
|
-
import
|
|
2358
|
-
import * as fs10 from "fs";
|
|
2359
|
-
import * as path10 from "path";
|
|
2640
|
+
import { confirm as confirm4, spinner as spinner5, note as note6, outro as outro5, cancel as cancel5, isCancel as isCancel6 } from "@clack/prompts";
|
|
2641
|
+
import pc7 from "picocolors";
|
|
2642
|
+
import * as fs14 from "fs";
|
|
2643
|
+
import * as path14 from "path";
|
|
2360
2644
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
2361
|
-
const s =
|
|
2645
|
+
const s = spinner5();
|
|
2362
2646
|
s.start("Checking for updates");
|
|
2363
2647
|
try {
|
|
2364
2648
|
const agentCoreDir = getAgentCoreDir();
|
|
@@ -2367,7 +2651,7 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
|
2367
2651
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
2368
2652
|
const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
|
|
2369
2653
|
s.stop("Updates found");
|
|
2370
|
-
|
|
2654
|
+
note6(
|
|
2371
2655
|
`The following will be updated from the package:
|
|
2372
2656
|
\u2022 prompts/ (${prompts.length} agent prompts)
|
|
2373
2657
|
\u2022 templates/ (output templates)
|
|
@@ -2376,20 +2660,20 @@ Target locations:
|
|
|
2376
2660
|
${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
2377
2661
|
"Update Preview"
|
|
2378
2662
|
);
|
|
2379
|
-
const shouldUpdate = await
|
|
2663
|
+
const shouldUpdate = await confirm4({
|
|
2380
2664
|
message: "Proceed with update?",
|
|
2381
2665
|
initialValue: true
|
|
2382
2666
|
});
|
|
2383
|
-
if (
|
|
2384
|
-
|
|
2667
|
+
if (isCancel6(shouldUpdate) || !shouldUpdate) {
|
|
2668
|
+
outro5("Update cancelled.");
|
|
2385
2669
|
return;
|
|
2386
2670
|
}
|
|
2387
2671
|
s.start("Updating from package");
|
|
2388
2672
|
for (const dataPath of dataPaths) {
|
|
2389
|
-
copyDirToAllStoragePaths(
|
|
2673
|
+
copyDirToAllStoragePaths(path14.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
2390
2674
|
}
|
|
2391
2675
|
const configFilePath = getConfigPath(workspacePath);
|
|
2392
|
-
const configContent =
|
|
2676
|
+
const configContent = fs14.readFileSync(configFilePath, "utf-8");
|
|
2393
2677
|
if (configContent.includes("copilot: true")) {
|
|
2394
2678
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
2395
2679
|
ensureDir(copilotPath);
|
|
@@ -2408,17 +2692,17 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
2408
2692
|
``,
|
|
2409
2693
|
`Your configuration and knowledge files were preserved.`
|
|
2410
2694
|
];
|
|
2411
|
-
|
|
2412
|
-
|
|
2695
|
+
note6(summary.join("\n"), "Update Summary");
|
|
2696
|
+
outro5(pc7.green("\u2713 Successfully updated from package!"));
|
|
2413
2697
|
} catch (error) {
|
|
2414
2698
|
s.stop("Error occurred");
|
|
2415
|
-
|
|
2699
|
+
cancel5(`Failed to update: ${error instanceof Error ? error.message : String(error)}`);
|
|
2416
2700
|
process.exit(1);
|
|
2417
2701
|
}
|
|
2418
2702
|
}
|
|
2419
2703
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
2420
|
-
const globalPath =
|
|
2421
|
-
const workspacePath =
|
|
2704
|
+
const globalPath = path14.join(customGlobalPath, "workspaces", workspaceName);
|
|
2705
|
+
const workspacePath = path14.join(workspaceRoot, ".rrce-workflow");
|
|
2422
2706
|
switch (mode) {
|
|
2423
2707
|
case "global":
|
|
2424
2708
|
return [globalPath];
|
|
@@ -2428,20 +2712,35 @@ function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot,
|
|
|
2428
2712
|
return [globalPath];
|
|
2429
2713
|
}
|
|
2430
2714
|
}
|
|
2715
|
+
var init_update_flow = __esm({
|
|
2716
|
+
"src/commands/wizard/update-flow.ts"() {
|
|
2717
|
+
"use strict";
|
|
2718
|
+
init_paths();
|
|
2719
|
+
init_prompts();
|
|
2720
|
+
init_utils();
|
|
2721
|
+
}
|
|
2722
|
+
});
|
|
2431
2723
|
|
|
2432
2724
|
// src/commands/wizard/index.ts
|
|
2725
|
+
var wizard_exports = {};
|
|
2726
|
+
__export(wizard_exports, {
|
|
2727
|
+
runWizard: () => runWizard
|
|
2728
|
+
});
|
|
2729
|
+
import { intro as intro2, select as select4, spinner as spinner6, note as note7, outro as outro6, isCancel as isCancel7 } from "@clack/prompts";
|
|
2730
|
+
import pc8 from "picocolors";
|
|
2731
|
+
import * as fs15 from "fs";
|
|
2433
2732
|
async function runWizard() {
|
|
2434
|
-
|
|
2435
|
-
const s =
|
|
2733
|
+
intro2(pc8.cyan(pc8.inverse(" RRCE-Workflow Setup ")));
|
|
2734
|
+
const s = spinner6();
|
|
2436
2735
|
s.start("Detecting environment");
|
|
2437
2736
|
const workspacePath = detectWorkspaceRoot();
|
|
2438
2737
|
const workspaceName = getWorkspaceName(workspacePath);
|
|
2439
2738
|
const gitUser = getGitUser();
|
|
2440
2739
|
await new Promise((r) => setTimeout(r, 800));
|
|
2441
2740
|
s.stop("Environment detected");
|
|
2442
|
-
|
|
2443
|
-
`Git User: ${
|
|
2444
|
-
Workspace: ${
|
|
2741
|
+
note7(
|
|
2742
|
+
`Git User: ${pc8.bold(gitUser || "(not found)")}
|
|
2743
|
+
Workspace: ${pc8.bold(workspaceName)}`,
|
|
2445
2744
|
"Context"
|
|
2446
2745
|
);
|
|
2447
2746
|
const detectedProjects = scanForProjects({
|
|
@@ -2449,44 +2748,53 @@ Workspace: ${pc7.bold(workspaceName)}`,
|
|
|
2449
2748
|
workspacePath
|
|
2450
2749
|
});
|
|
2451
2750
|
const configFilePath = getConfigPath(workspacePath);
|
|
2452
|
-
const isAlreadyConfigured =
|
|
2751
|
+
const isAlreadyConfigured = fs15.existsSync(configFilePath);
|
|
2453
2752
|
let currentStorageMode = null;
|
|
2454
2753
|
if (isAlreadyConfigured) {
|
|
2455
2754
|
try {
|
|
2456
|
-
const configContent =
|
|
2755
|
+
const configContent = fs15.readFileSync(configFilePath, "utf-8");
|
|
2457
2756
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
2458
2757
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
2459
2758
|
} catch {
|
|
2460
2759
|
}
|
|
2461
2760
|
}
|
|
2462
2761
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
2463
|
-
const hasLocalData =
|
|
2762
|
+
const hasLocalData = fs15.existsSync(localDataPath);
|
|
2464
2763
|
if (isAlreadyConfigured) {
|
|
2465
2764
|
const menuOptions = [];
|
|
2765
|
+
menuOptions.push({
|
|
2766
|
+
value: "mcp",
|
|
2767
|
+
label: "\u{1F50C} Configure MCP Server",
|
|
2768
|
+
hint: "Expose projects to AI assistants (VSCode, Antigravity, Claude)"
|
|
2769
|
+
});
|
|
2466
2770
|
if (detectedProjects.length > 0) {
|
|
2467
2771
|
menuOptions.push({
|
|
2468
2772
|
value: "link",
|
|
2469
|
-
label: "Link other project knowledge",
|
|
2773
|
+
label: "\u{1F517} Link other project knowledge",
|
|
2470
2774
|
hint: `${detectedProjects.length} projects detected (global + sibling)`
|
|
2471
2775
|
});
|
|
2472
2776
|
}
|
|
2473
2777
|
if (currentStorageMode === "workspace" && hasLocalData) {
|
|
2474
2778
|
menuOptions.push({
|
|
2475
2779
|
value: "sync-global",
|
|
2476
|
-
label: "Sync to global storage",
|
|
2780
|
+
label: "\u2601\uFE0F Sync to global storage",
|
|
2477
2781
|
hint: "Share knowledge with other projects"
|
|
2478
2782
|
});
|
|
2479
2783
|
}
|
|
2480
|
-
menuOptions.push({ value: "update", label: "Update from package", hint: "Get latest prompts & templates" });
|
|
2481
|
-
menuOptions.push({ value: "exit", label: "Exit" });
|
|
2482
|
-
const action = await
|
|
2784
|
+
menuOptions.push({ value: "update", label: "\u{1F4E6} Update from package", hint: "Get latest prompts & templates" });
|
|
2785
|
+
menuOptions.push({ value: "exit", label: "\u21A9 Exit" });
|
|
2786
|
+
const action = await select4({
|
|
2483
2787
|
message: "This workspace is already configured. What would you like to do?",
|
|
2484
2788
|
options: menuOptions
|
|
2485
2789
|
});
|
|
2486
|
-
if (
|
|
2487
|
-
|
|
2790
|
+
if (isCancel7(action) || action === "exit") {
|
|
2791
|
+
outro6("Exited.");
|
|
2488
2792
|
process.exit(0);
|
|
2489
2793
|
}
|
|
2794
|
+
if (action === "mcp") {
|
|
2795
|
+
await runMCP();
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2490
2798
|
if (action === "link") {
|
|
2491
2799
|
await runLinkProjectsFlow(workspacePath, workspaceName);
|
|
2492
2800
|
return;
|
|
@@ -2502,6 +2810,22 @@ Workspace: ${pc7.bold(workspaceName)}`,
|
|
|
2502
2810
|
}
|
|
2503
2811
|
await runSetupFlow(workspacePath, workspaceName, detectedProjects);
|
|
2504
2812
|
}
|
|
2813
|
+
var init_wizard = __esm({
|
|
2814
|
+
"src/commands/wizard/index.ts"() {
|
|
2815
|
+
"use strict";
|
|
2816
|
+
init_git();
|
|
2817
|
+
init_paths();
|
|
2818
|
+
init_detection();
|
|
2819
|
+
init_setup_flow();
|
|
2820
|
+
init_link_flow();
|
|
2821
|
+
init_sync_flow();
|
|
2822
|
+
init_update_flow();
|
|
2823
|
+
init_mcp();
|
|
2824
|
+
}
|
|
2825
|
+
});
|
|
2826
|
+
|
|
2827
|
+
// src/index.ts
|
|
2828
|
+
init_wizard();
|
|
2505
2829
|
|
|
2506
2830
|
// src/commands/selector.ts
|
|
2507
2831
|
init_prompts();
|
|
@@ -2521,9 +2845,14 @@ async function runSelector() {
|
|
|
2521
2845
|
options: [
|
|
2522
2846
|
{
|
|
2523
2847
|
value: "mcp",
|
|
2524
|
-
label: "Manage MCP Hub",
|
|
2848
|
+
label: "\u{1F50C} Manage MCP Hub",
|
|
2525
2849
|
hint: "Configure & Start MCP Server"
|
|
2526
2850
|
},
|
|
2851
|
+
{
|
|
2852
|
+
value: "wizard",
|
|
2853
|
+
label: "\u2728 Run Setup Wizard",
|
|
2854
|
+
hint: "Configure workspace & agents"
|
|
2855
|
+
},
|
|
2527
2856
|
...prompts.map((p) => ({
|
|
2528
2857
|
value: p,
|
|
2529
2858
|
label: p.frontmatter.name,
|
|
@@ -2540,6 +2869,11 @@ async function runSelector() {
|
|
|
2540
2869
|
await runMCP2();
|
|
2541
2870
|
return;
|
|
2542
2871
|
}
|
|
2872
|
+
if (selection === "wizard") {
|
|
2873
|
+
const { runWizard: runWizard2 } = await Promise.resolve().then(() => (init_wizard(), wizard_exports));
|
|
2874
|
+
await runWizard2();
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2543
2877
|
const prompt = selection;
|
|
2544
2878
|
note8(
|
|
2545
2879
|
`Use this agent in your IDE by invoking:
|