rrce-workflow 0.2.68 → 0.2.69
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/agent-core/docs/path-resolution.md +92 -0
- package/agent-core/prompts/doctor.md +167 -105
- package/agent-core/prompts/documentation.md +15 -17
- package/agent-core/prompts/executor.md +30 -19
- package/agent-core/prompts/init.md +165 -171
- package/agent-core/prompts/planning_orchestrator.md +14 -19
- package/agent-core/prompts/research_discussion.md +187 -57
- package/agent-core/prompts/sync.md +11 -22
- package/agent-core/templates/doctor_output.md +18 -7
- package/agent-core/templates/documentation_output.md +23 -7
- package/agent-core/templates/executor_output.md +21 -7
- package/agent-core/templates/init_output.md +27 -7
- package/agent-core/templates/planning_output.md +19 -7
- package/agent-core/templates/research_output.md +19 -7
- package/dist/index.js +2034 -1939
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
3
9
|
var __esm = (fn, res) => function __init() {
|
|
4
10
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
11
|
};
|
|
@@ -672,2168 +678,2240 @@ var init_tui_utils = __esm({
|
|
|
672
678
|
}
|
|
673
679
|
});
|
|
674
680
|
|
|
675
|
-
// src/
|
|
676
|
-
import
|
|
677
|
-
import
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
if (isCancel2(result)) {
|
|
688
|
-
cancel("Setup cancelled.");
|
|
689
|
-
process.exit(0);
|
|
690
|
-
}
|
|
691
|
-
return result;
|
|
681
|
+
// src/mcp/install.ts
|
|
682
|
+
import * as fs5 from "fs";
|
|
683
|
+
import * as path6 from "path";
|
|
684
|
+
import * as os from "os";
|
|
685
|
+
function checkInstallStatus(workspacePath) {
|
|
686
|
+
return {
|
|
687
|
+
antigravity: checkAntigravityConfig(),
|
|
688
|
+
claude: checkClaudeConfig(),
|
|
689
|
+
vscodeGlobal: checkVSCodeGlobalConfig(),
|
|
690
|
+
vscodeWorkspace: workspacePath ? checkVSCodeWorkspaceConfig(workspacePath) : false,
|
|
691
|
+
opencode: checkOpenCodeConfig()
|
|
692
|
+
};
|
|
692
693
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
required: false
|
|
701
|
-
});
|
|
702
|
-
if (isCancel2(result)) {
|
|
703
|
-
cancel("Setup cancelled.");
|
|
704
|
-
process.exit(0);
|
|
694
|
+
function checkAntigravityConfig() {
|
|
695
|
+
if (!fs5.existsSync(ANTIGRAVITY_CONFIG)) return false;
|
|
696
|
+
try {
|
|
697
|
+
const content = JSON.parse(fs5.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
698
|
+
return !!content.mcpServers?.["rrce"];
|
|
699
|
+
} catch {
|
|
700
|
+
return false;
|
|
705
701
|
}
|
|
706
|
-
return result;
|
|
707
702
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
process.exit(0);
|
|
703
|
+
function checkClaudeConfig() {
|
|
704
|
+
if (!fs5.existsSync(CLAUDE_CONFIG)) return false;
|
|
705
|
+
try {
|
|
706
|
+
const content = JSON.parse(fs5.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
707
|
+
return !!content.mcpServers?.["rrce"];
|
|
708
|
+
} catch {
|
|
709
|
+
return false;
|
|
716
710
|
}
|
|
717
|
-
return result;
|
|
718
711
|
}
|
|
719
|
-
|
|
720
|
-
if (
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
value: `${project.name}:${project.source}`,
|
|
727
|
-
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
728
|
-
hint: pc3.dim(
|
|
729
|
-
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
730
|
-
)
|
|
731
|
-
})),
|
|
732
|
-
required: false
|
|
733
|
-
});
|
|
734
|
-
if (isCancel2(result)) {
|
|
735
|
-
cancel("Setup cancelled.");
|
|
736
|
-
process.exit(0);
|
|
712
|
+
function checkVSCodeGlobalConfig() {
|
|
713
|
+
if (!fs5.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
|
|
714
|
+
try {
|
|
715
|
+
const content = JSON.parse(fs5.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
716
|
+
return !!content["mcp.servers"]?.["rrce"];
|
|
717
|
+
} catch {
|
|
718
|
+
return false;
|
|
737
719
|
}
|
|
738
|
-
return result;
|
|
739
720
|
}
|
|
740
|
-
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
721
|
+
function checkVSCodeWorkspaceConfig(workspacePath) {
|
|
722
|
+
const configPath = path6.join(workspacePath, ".vscode", "mcp.json");
|
|
723
|
+
if (!fs5.existsSync(configPath)) return false;
|
|
724
|
+
try {
|
|
725
|
+
const content = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
726
|
+
return !!content.servers?.["rrce"];
|
|
727
|
+
} catch {
|
|
728
|
+
return false;
|
|
748
729
|
}
|
|
749
|
-
return result;
|
|
750
730
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
cancel("Setup cancelled.");
|
|
759
|
-
process.exit(0);
|
|
731
|
+
function checkOpenCodeConfig() {
|
|
732
|
+
if (!fs5.existsSync(OPENCODE_CONFIG)) return false;
|
|
733
|
+
try {
|
|
734
|
+
const content = JSON.parse(fs5.readFileSync(OPENCODE_CONFIG, "utf-8"));
|
|
735
|
+
return !!content.mcp?.["rrce"];
|
|
736
|
+
} catch {
|
|
737
|
+
return false;
|
|
760
738
|
}
|
|
761
|
-
return result;
|
|
762
739
|
}
|
|
763
|
-
|
|
764
|
-
const
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
740
|
+
function isInstalledAnywhere(workspacePath) {
|
|
741
|
+
const status = checkInstallStatus(workspacePath);
|
|
742
|
+
return status.antigravity || status.claude || status.vscodeGlobal || status.vscodeWorkspace || status.opencode;
|
|
743
|
+
}
|
|
744
|
+
function installToConfig(target, workspacePath) {
|
|
745
|
+
switch (target) {
|
|
746
|
+
case "antigravity":
|
|
747
|
+
return installToAntigravity();
|
|
748
|
+
case "claude":
|
|
749
|
+
return installToClaude();
|
|
750
|
+
case "vscode-global":
|
|
751
|
+
return installToVSCodeGlobal();
|
|
752
|
+
case "vscode-workspace":
|
|
753
|
+
return workspacePath ? installToVSCodeWorkspace(workspacePath) : false;
|
|
754
|
+
case "opencode":
|
|
755
|
+
return installToOpenCode();
|
|
756
|
+
default:
|
|
757
|
+
return false;
|
|
771
758
|
}
|
|
772
|
-
return result;
|
|
773
759
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
760
|
+
function installToAntigravity() {
|
|
761
|
+
const dir = path6.dirname(ANTIGRAVITY_CONFIG);
|
|
762
|
+
if (!fs5.existsSync(dir)) {
|
|
763
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
777
764
|
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
"src/types/prompt.ts"() {
|
|
785
|
-
"use strict";
|
|
786
|
-
PromptArgSchema = z.object({
|
|
787
|
-
name: z.string(),
|
|
788
|
-
default: z.string().optional(),
|
|
789
|
-
prompt: z.string().optional()
|
|
790
|
-
});
|
|
791
|
-
AutoIdentitySchema = z.object({
|
|
792
|
-
user: z.string(),
|
|
793
|
-
model: z.string()
|
|
794
|
-
});
|
|
795
|
-
PromptFrontmatterSchema = z.object({
|
|
796
|
-
name: z.string(),
|
|
797
|
-
description: z.string(),
|
|
798
|
-
"argument-hint": z.union([z.string(), z.array(z.string())]).optional(),
|
|
799
|
-
tools: z.array(z.string()).optional(),
|
|
800
|
-
"required-args": z.array(PromptArgSchema).optional(),
|
|
801
|
-
"optional-args": z.array(PromptArgSchema).optional(),
|
|
802
|
-
"auto-identity": AutoIdentitySchema.optional()
|
|
803
|
-
});
|
|
765
|
+
let config = { mcpServers: {} };
|
|
766
|
+
if (fs5.existsSync(ANTIGRAVITY_CONFIG)) {
|
|
767
|
+
try {
|
|
768
|
+
config = JSON.parse(fs5.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
769
|
+
} catch {
|
|
770
|
+
}
|
|
804
771
|
}
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
import { fileURLToPath } from "url";
|
|
811
|
-
import matter from "gray-matter";
|
|
812
|
-
function parsePromptFile(filePath) {
|
|
772
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
773
|
+
config.mcpServers["rrce"] = {
|
|
774
|
+
command: "npx",
|
|
775
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
776
|
+
};
|
|
813
777
|
try {
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
console.error(`Failed to parse frontmatter in ${filePath}:`, parsed.error);
|
|
819
|
-
return null;
|
|
820
|
-
}
|
|
821
|
-
return {
|
|
822
|
-
frontmatter: parsed.data,
|
|
823
|
-
content: content.trim(),
|
|
824
|
-
filePath
|
|
825
|
-
};
|
|
826
|
-
} catch (error) {
|
|
827
|
-
console.error(`Error reading prompt file ${filePath}:`, error);
|
|
828
|
-
return null;
|
|
778
|
+
fs5.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
|
|
779
|
+
return true;
|
|
780
|
+
} catch {
|
|
781
|
+
return false;
|
|
829
782
|
}
|
|
830
783
|
}
|
|
831
|
-
function
|
|
832
|
-
|
|
833
|
-
|
|
784
|
+
function installToClaude() {
|
|
785
|
+
const dir = path6.dirname(CLAUDE_CONFIG);
|
|
786
|
+
if (!fs5.existsSync(dir)) {
|
|
787
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
834
788
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
prompts.push(prompt);
|
|
789
|
+
let config = { mcpServers: {} };
|
|
790
|
+
if (fs5.existsSync(CLAUDE_CONFIG)) {
|
|
791
|
+
try {
|
|
792
|
+
config = JSON.parse(fs5.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
793
|
+
} catch {
|
|
841
794
|
}
|
|
842
795
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
return
|
|
796
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
797
|
+
config.mcpServers["rrce"] = {
|
|
798
|
+
command: "npx",
|
|
799
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
800
|
+
};
|
|
801
|
+
try {
|
|
802
|
+
fs5.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
|
|
803
|
+
return true;
|
|
804
|
+
} catch {
|
|
805
|
+
return false;
|
|
851
806
|
}
|
|
852
|
-
return path6.join(__dirname, "..", "agent-core");
|
|
853
807
|
}
|
|
854
|
-
function
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
var init_prompts = __esm({
|
|
859
|
-
"src/lib/prompts.ts"() {
|
|
860
|
-
"use strict";
|
|
861
|
-
init_prompt();
|
|
862
|
-
__filename = fileURLToPath(import.meta.url);
|
|
863
|
-
__dirname = path6.dirname(__filename);
|
|
864
|
-
}
|
|
865
|
-
});
|
|
866
|
-
|
|
867
|
-
// src/commands/wizard/utils.ts
|
|
868
|
-
import * as fs6 from "fs";
|
|
869
|
-
import * as path7 from "path";
|
|
870
|
-
function copyPromptsToDir(prompts, targetDir, extension) {
|
|
871
|
-
for (const prompt of prompts) {
|
|
872
|
-
const baseName = path7.basename(prompt.filePath, ".md");
|
|
873
|
-
const targetName = baseName + extension;
|
|
874
|
-
const targetPath = path7.join(targetDir, targetName);
|
|
875
|
-
const content = fs6.readFileSync(prompt.filePath, "utf-8");
|
|
876
|
-
fs6.writeFileSync(targetPath, content);
|
|
808
|
+
function installToVSCodeGlobal() {
|
|
809
|
+
const dir = path6.dirname(VSCODE_GLOBAL_CONFIG);
|
|
810
|
+
if (!fs5.existsSync(dir)) {
|
|
811
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
877
812
|
}
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
const destPath = path7.join(dest, entry.name);
|
|
884
|
-
if (entry.isDirectory()) {
|
|
885
|
-
ensureDir(destPath);
|
|
886
|
-
copyDirRecursive(srcPath, destPath);
|
|
887
|
-
} else {
|
|
888
|
-
fs6.copyFileSync(srcPath, destPath);
|
|
813
|
+
let settings = {};
|
|
814
|
+
if (fs5.existsSync(VSCODE_GLOBAL_CONFIG)) {
|
|
815
|
+
try {
|
|
816
|
+
settings = JSON.parse(fs5.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
817
|
+
} catch {
|
|
889
818
|
}
|
|
890
819
|
}
|
|
820
|
+
if (!settings["mcp.servers"]) settings["mcp.servers"] = {};
|
|
821
|
+
settings["mcp.servers"]["rrce"] = {
|
|
822
|
+
command: "npx",
|
|
823
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
824
|
+
};
|
|
825
|
+
try {
|
|
826
|
+
fs5.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
|
|
827
|
+
return true;
|
|
828
|
+
} catch {
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
891
831
|
}
|
|
892
|
-
|
|
893
|
-
"
|
|
894
|
-
|
|
895
|
-
|
|
832
|
+
function installToVSCodeWorkspace(workspacePath) {
|
|
833
|
+
const vscodeDir = path6.join(workspacePath, ".vscode");
|
|
834
|
+
const configPath = path6.join(vscodeDir, "mcp.json");
|
|
835
|
+
if (!fs5.existsSync(vscodeDir)) {
|
|
836
|
+
fs5.mkdirSync(vscodeDir, { recursive: true });
|
|
896
837
|
}
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
// src/commands/wizard/vscode.ts
|
|
900
|
-
import * as fs7 from "fs";
|
|
901
|
-
import * as path8 from "path";
|
|
902
|
-
function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
903
|
-
const workspaceFilePath = path8.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
904
|
-
let workspace;
|
|
905
|
-
if (fs7.existsSync(workspaceFilePath)) {
|
|
838
|
+
let config = { servers: {} };
|
|
839
|
+
if (fs5.existsSync(configPath)) {
|
|
906
840
|
try {
|
|
907
|
-
|
|
908
|
-
workspace = JSON.parse(content);
|
|
841
|
+
config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
909
842
|
} catch {
|
|
910
|
-
workspace = { folders: [], settings: {} };
|
|
911
843
|
}
|
|
912
|
-
} else {
|
|
913
|
-
workspace = { folders: [], settings: {} };
|
|
914
844
|
}
|
|
915
|
-
if (!
|
|
916
|
-
|
|
845
|
+
if (!config.servers) config.servers = {};
|
|
846
|
+
config.servers["rrce"] = {
|
|
847
|
+
command: "npx",
|
|
848
|
+
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
849
|
+
};
|
|
850
|
+
try {
|
|
851
|
+
fs5.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
852
|
+
return true;
|
|
853
|
+
} catch {
|
|
854
|
+
return false;
|
|
917
855
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
);
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
workspace.folders.unshift({
|
|
924
|
-
path: ".",
|
|
925
|
-
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
926
|
-
});
|
|
927
|
-
} else {
|
|
928
|
-
workspace.folders[mainFolderIndex] = {
|
|
929
|
-
path: ".",
|
|
930
|
-
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
931
|
-
};
|
|
856
|
+
}
|
|
857
|
+
function installToOpenCode() {
|
|
858
|
+
const dir = path6.dirname(OPENCODE_CONFIG);
|
|
859
|
+
if (!fs5.existsSync(dir)) {
|
|
860
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
932
861
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
referenceFolderPaths.push(folderPath);
|
|
942
|
-
workspace.folders.push({
|
|
943
|
-
path: folderPath,
|
|
944
|
-
name: `\u{1F4C1} ${project.name} [${sourceLabel}]`
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
} else {
|
|
949
|
-
const projectNames = linkedProjects;
|
|
950
|
-
const rrceHome = customGlobalPath || getRRCEHome();
|
|
951
|
-
for (const projectName of projectNames) {
|
|
952
|
-
const folderPath = path8.join(rrceHome, "workspaces", projectName);
|
|
953
|
-
if (fs7.existsSync(folderPath)) {
|
|
954
|
-
referenceFolderPaths.push(folderPath);
|
|
955
|
-
workspace.folders.push({
|
|
956
|
-
path: folderPath,
|
|
957
|
-
name: `\u{1F4C1} ${projectName} [global]`
|
|
958
|
-
});
|
|
959
|
-
}
|
|
862
|
+
let config = {
|
|
863
|
+
$schema: "https://opencode.ai/config.json"
|
|
864
|
+
};
|
|
865
|
+
if (fs5.existsSync(OPENCODE_CONFIG)) {
|
|
866
|
+
try {
|
|
867
|
+
config = JSON.parse(fs5.readFileSync(OPENCODE_CONFIG, "utf-8"));
|
|
868
|
+
} catch (error) {
|
|
869
|
+
console.error("Warning: Could not parse existing OpenCode config, creating fresh config");
|
|
960
870
|
}
|
|
961
871
|
}
|
|
962
|
-
if (
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
workspace.settings["files.readonlyInclude"] = {
|
|
975
|
-
...cleanedReadonly,
|
|
976
|
-
...readonlyPatterns
|
|
977
|
-
};
|
|
872
|
+
if (!config.mcp) config.mcp = {};
|
|
873
|
+
config.mcp["rrce"] = {
|
|
874
|
+
type: "local",
|
|
875
|
+
command: ["npx", "-y", "rrce-workflow", "mcp", "start"],
|
|
876
|
+
enabled: true
|
|
877
|
+
};
|
|
878
|
+
try {
|
|
879
|
+
fs5.writeFileSync(OPENCODE_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
880
|
+
return true;
|
|
881
|
+
} catch (error) {
|
|
882
|
+
console.error("Failed to write OpenCode config:", error instanceof Error ? error.message : String(error));
|
|
883
|
+
return false;
|
|
978
884
|
}
|
|
979
|
-
fs7.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
980
885
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
"
|
|
984
|
-
|
|
985
|
-
init_detection();
|
|
986
|
-
}
|
|
987
|
-
});
|
|
988
|
-
|
|
989
|
-
// src/mcp/types.ts
|
|
990
|
-
var DEFAULT_MCP_CONFIG, DEFAULT_PERMISSIONS;
|
|
991
|
-
var init_types = __esm({
|
|
992
|
-
"src/mcp/types.ts"() {
|
|
993
|
-
"use strict";
|
|
994
|
-
DEFAULT_MCP_CONFIG = {
|
|
995
|
-
server: {
|
|
996
|
-
port: 3e3,
|
|
997
|
-
autoStart: false
|
|
998
|
-
},
|
|
999
|
-
projects: [],
|
|
1000
|
-
defaults: {
|
|
1001
|
-
includeNew: true,
|
|
1002
|
-
permissions: {
|
|
1003
|
-
knowledge: true,
|
|
1004
|
-
tasks: true,
|
|
1005
|
-
refs: true
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
};
|
|
1009
|
-
DEFAULT_PERMISSIONS = {
|
|
1010
|
-
knowledge: true,
|
|
1011
|
-
tasks: true,
|
|
1012
|
-
refs: true
|
|
1013
|
-
};
|
|
886
|
+
function uninstallFromOpenCode() {
|
|
887
|
+
if (!fs5.existsSync(OPENCODE_CONFIG)) {
|
|
888
|
+
console.error("OpenCode config not found");
|
|
889
|
+
return false;
|
|
1014
890
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
if (identifier.path && p.path) {
|
|
1021
|
-
return p.path === identifier.path;
|
|
1022
|
-
}
|
|
1023
|
-
if (!identifier.path && !p.path) {
|
|
1024
|
-
return p.name === identifier.name;
|
|
1025
|
-
}
|
|
1026
|
-
if (identifier.path && !p.path) {
|
|
1027
|
-
return p.name === identifier.name;
|
|
891
|
+
try {
|
|
892
|
+
const config = JSON.parse(fs5.readFileSync(OPENCODE_CONFIG, "utf-8"));
|
|
893
|
+
if (!config.mcp?.["rrce"]) {
|
|
894
|
+
console.warn("RRCE not found in OpenCode config");
|
|
895
|
+
return false;
|
|
1028
896
|
}
|
|
897
|
+
delete config.mcp["rrce"];
|
|
898
|
+
fs5.writeFileSync(OPENCODE_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
899
|
+
return true;
|
|
900
|
+
} catch (error) {
|
|
901
|
+
console.error("Failed to uninstall from OpenCode:", error instanceof Error ? error.message : String(error));
|
|
1029
902
|
return false;
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
var init_config_utils = __esm({
|
|
1033
|
-
"src/mcp/config-utils.ts"() {
|
|
1034
|
-
"use strict";
|
|
1035
903
|
}
|
|
1036
|
-
});
|
|
1037
|
-
|
|
1038
|
-
// src/mcp/config.ts
|
|
1039
|
-
var config_exports = {};
|
|
1040
|
-
__export(config_exports, {
|
|
1041
|
-
cleanStaleProjects: () => cleanStaleProjects,
|
|
1042
|
-
ensureMCPGlobalPath: () => ensureMCPGlobalPath,
|
|
1043
|
-
getMCPConfigPath: () => getMCPConfigPath,
|
|
1044
|
-
getProjectPermissions: () => getProjectPermissions,
|
|
1045
|
-
isProjectExposed: () => isProjectExposed,
|
|
1046
|
-
loadMCPConfig: () => loadMCPConfig,
|
|
1047
|
-
removeProjectConfig: () => removeProjectConfig,
|
|
1048
|
-
saveMCPConfig: () => saveMCPConfig,
|
|
1049
|
-
setProjectConfig: () => setProjectConfig
|
|
1050
|
-
});
|
|
1051
|
-
import * as fs8 from "fs";
|
|
1052
|
-
import * as path9 from "path";
|
|
1053
|
-
import YAML from "yaml";
|
|
1054
|
-
function getMCPConfigPath() {
|
|
1055
|
-
const workspaceRoot = detectWorkspaceRoot();
|
|
1056
|
-
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1057
|
-
return path9.join(rrceHome, "mcp.yaml");
|
|
1058
904
|
}
|
|
1059
|
-
function
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
configured: false,
|
|
1070
|
-
path: rrceHome,
|
|
1071
|
-
reason: "Workspace mode configured. MCP requires a global storage path."
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
905
|
+
function uninstallFromAntigravity() {
|
|
906
|
+
if (!fs5.existsSync(ANTIGRAVITY_CONFIG)) {
|
|
907
|
+
console.error("Antigravity config not found");
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
try {
|
|
911
|
+
const config = JSON.parse(fs5.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
912
|
+
if (!config.mcpServers?.["rrce"]) {
|
|
913
|
+
console.warn("RRCE not found in Antigravity config");
|
|
914
|
+
return false;
|
|
1074
915
|
}
|
|
916
|
+
delete config.mcpServers["rrce"];
|
|
917
|
+
fs5.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
918
|
+
return true;
|
|
919
|
+
} catch (error) {
|
|
920
|
+
console.error("Failed to uninstall from Antigravity:", error instanceof Error ? error.message : String(error));
|
|
921
|
+
return false;
|
|
1075
922
|
}
|
|
1076
|
-
return {
|
|
1077
|
-
configured: true,
|
|
1078
|
-
path: rrceHome
|
|
1079
|
-
};
|
|
1080
923
|
}
|
|
1081
|
-
function
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
return
|
|
924
|
+
function uninstallFromClaude() {
|
|
925
|
+
if (!fs5.existsSync(CLAUDE_CONFIG)) {
|
|
926
|
+
console.error("Claude Desktop config not found");
|
|
927
|
+
return false;
|
|
1085
928
|
}
|
|
1086
929
|
try {
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
930
|
+
const config = JSON.parse(fs5.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
931
|
+
if (!config.mcpServers?.["rrce"]) {
|
|
932
|
+
console.warn("RRCE not found in Claude Desktop config");
|
|
933
|
+
return false;
|
|
934
|
+
}
|
|
935
|
+
delete config.mcpServers["rrce"];
|
|
936
|
+
fs5.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
937
|
+
return true;
|
|
938
|
+
} catch (error) {
|
|
939
|
+
console.error("Failed to uninstall from Claude Desktop:", error instanceof Error ? error.message : String(error));
|
|
940
|
+
return false;
|
|
1091
941
|
}
|
|
1092
942
|
}
|
|
1093
|
-
function
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
fs8.mkdirSync(dir, { recursive: true });
|
|
943
|
+
function uninstallFromVSCodeGlobal() {
|
|
944
|
+
if (!fs5.existsSync(VSCODE_GLOBAL_CONFIG)) {
|
|
945
|
+
console.error("VSCode global config not found");
|
|
946
|
+
return false;
|
|
1098
947
|
}
|
|
1099
|
-
const content = serializeMCPConfig(config);
|
|
1100
|
-
fs8.writeFileSync(configPath, content);
|
|
1101
|
-
}
|
|
1102
|
-
function parseMCPConfig(content) {
|
|
1103
948
|
try {
|
|
1104
|
-
const
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
refs: parsed?.defaults?.permissions?.refs ?? DEFAULT_PERMISSIONS.refs
|
|
1116
|
-
}
|
|
1117
|
-
},
|
|
1118
|
-
projects: Array.isArray(parsed?.projects) ? parsed.projects.map((p) => ({
|
|
1119
|
-
name: p.name || "",
|
|
1120
|
-
path: p.path,
|
|
1121
|
-
expose: p.expose ?? true,
|
|
1122
|
-
permissions: {
|
|
1123
|
-
knowledge: p.permissions?.knowledge ?? DEFAULT_PERMISSIONS.knowledge,
|
|
1124
|
-
tasks: p.permissions?.tasks ?? DEFAULT_PERMISSIONS.tasks,
|
|
1125
|
-
refs: p.permissions?.refs ?? DEFAULT_PERMISSIONS.refs
|
|
1126
|
-
},
|
|
1127
|
-
semanticSearch: p.semanticSearch
|
|
1128
|
-
})) : []
|
|
1129
|
-
};
|
|
1130
|
-
return config;
|
|
1131
|
-
} catch (err) {
|
|
1132
|
-
return { ...DEFAULT_MCP_CONFIG };
|
|
949
|
+
const settings = JSON.parse(fs5.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
950
|
+
if (!settings["mcp.servers"]?.["rrce"]) {
|
|
951
|
+
console.warn("RRCE not found in VSCode global settings");
|
|
952
|
+
return false;
|
|
953
|
+
}
|
|
954
|
+
delete settings["mcp.servers"]["rrce"];
|
|
955
|
+
fs5.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2) + "\n");
|
|
956
|
+
return true;
|
|
957
|
+
} catch (error) {
|
|
958
|
+
console.error("Failed to uninstall from VSCode (Global):", error instanceof Error ? error.message : String(error));
|
|
959
|
+
return false;
|
|
1133
960
|
}
|
|
1134
961
|
}
|
|
1135
|
-
function
|
|
1136
|
-
const
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
function setProjectConfig(config, name, expose, permissions, projectPath, semanticSearch) {
|
|
1147
|
-
const existing = findProjectConfig(config, { name, path: projectPath });
|
|
1148
|
-
if (existing) {
|
|
1149
|
-
existing.expose = expose;
|
|
1150
|
-
if (projectPath && !existing.path) {
|
|
1151
|
-
existing.path = projectPath;
|
|
1152
|
-
}
|
|
1153
|
-
if (permissions) {
|
|
1154
|
-
existing.permissions = { ...existing.permissions, ...permissions };
|
|
1155
|
-
}
|
|
1156
|
-
if (semanticSearch) {
|
|
1157
|
-
existing.semanticSearch = semanticSearch;
|
|
962
|
+
function uninstallFromVSCodeWorkspace(workspacePath) {
|
|
963
|
+
const configPath = path6.join(workspacePath, ".vscode", "mcp.json");
|
|
964
|
+
if (!fs5.existsSync(configPath)) {
|
|
965
|
+
console.error("VSCode workspace config not found");
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
try {
|
|
969
|
+
const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
|
|
970
|
+
if (!config.servers?.["rrce"]) {
|
|
971
|
+
console.warn("RRCE not found in VSCode workspace config");
|
|
972
|
+
return false;
|
|
1158
973
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
semanticSearch
|
|
1166
|
-
});
|
|
974
|
+
delete config.servers["rrce"];
|
|
975
|
+
fs5.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
976
|
+
return true;
|
|
977
|
+
} catch (error) {
|
|
978
|
+
console.error("Failed to uninstall from VSCode (Workspace):", error instanceof Error ? error.message : String(error));
|
|
979
|
+
return false;
|
|
1167
980
|
}
|
|
1168
|
-
return config;
|
|
1169
981
|
}
|
|
1170
|
-
function
|
|
1171
|
-
|
|
1172
|
-
|
|
982
|
+
function uninstallFromConfig(target, workspacePath) {
|
|
983
|
+
switch (target) {
|
|
984
|
+
case "antigravity":
|
|
985
|
+
return uninstallFromAntigravity();
|
|
986
|
+
case "claude":
|
|
987
|
+
return uninstallFromClaude();
|
|
988
|
+
case "vscode-global":
|
|
989
|
+
return uninstallFromVSCodeGlobal();
|
|
990
|
+
case "vscode-workspace":
|
|
991
|
+
return workspacePath ? uninstallFromVSCodeWorkspace(workspacePath) : false;
|
|
992
|
+
case "opencode":
|
|
993
|
+
return uninstallFromOpenCode();
|
|
994
|
+
default:
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
1173
997
|
}
|
|
1174
|
-
function
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
998
|
+
function getTargetLabel(target) {
|
|
999
|
+
switch (target) {
|
|
1000
|
+
case "antigravity":
|
|
1001
|
+
return "Antigravity IDE";
|
|
1002
|
+
case "claude":
|
|
1003
|
+
return "Claude Desktop";
|
|
1004
|
+
case "vscode-global":
|
|
1005
|
+
return "VSCode (Global)";
|
|
1006
|
+
case "vscode-workspace":
|
|
1007
|
+
return "VSCode (Workspace)";
|
|
1008
|
+
case "opencode":
|
|
1009
|
+
return "OpenCode";
|
|
1010
|
+
default:
|
|
1011
|
+
return target;
|
|
1178
1012
|
}
|
|
1179
|
-
return config.defaults.includeNew;
|
|
1180
1013
|
}
|
|
1181
|
-
function
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1014
|
+
function isOpenCodeInstalled() {
|
|
1015
|
+
const configDir = path6.join(os.homedir(), ".config/opencode");
|
|
1016
|
+
const configFile = path6.join(configDir, "opencode.json");
|
|
1017
|
+
return fs5.existsSync(configDir) || fs5.existsSync(configFile);
|
|
1184
1018
|
}
|
|
1185
|
-
function
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1188
|
-
const validProjects = [];
|
|
1189
|
-
const removed = [];
|
|
1190
|
-
for (const project of config.projects) {
|
|
1191
|
-
let exists = false;
|
|
1192
|
-
if (project.path) {
|
|
1193
|
-
exists = fs8.existsSync(project.path);
|
|
1194
|
-
} else {
|
|
1195
|
-
const globalPath = path9.join(globalWorkspacesDir, project.name);
|
|
1196
|
-
exists = fs8.existsSync(globalPath);
|
|
1197
|
-
}
|
|
1198
|
-
if (exists) {
|
|
1199
|
-
validProjects.push(project);
|
|
1200
|
-
} else {
|
|
1201
|
-
removed.push(project.name);
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
if (removed.length > 0) {
|
|
1205
|
-
config.projects = validProjects;
|
|
1206
|
-
}
|
|
1207
|
-
return { config, removed };
|
|
1019
|
+
function isAntigravityInstalled() {
|
|
1020
|
+
const configDir = path6.join(os.homedir(), ".gemini/antigravity");
|
|
1021
|
+
return fs5.existsSync(configDir);
|
|
1208
1022
|
}
|
|
1209
|
-
|
|
1210
|
-
"
|
|
1023
|
+
function isVSCodeInstalled() {
|
|
1024
|
+
const configDir = path6.join(os.homedir(), ".config/Code/User");
|
|
1025
|
+
return fs5.existsSync(configDir);
|
|
1026
|
+
}
|
|
1027
|
+
var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG, OPENCODE_CONFIG;
|
|
1028
|
+
var init_install = __esm({
|
|
1029
|
+
"src/mcp/install.ts"() {
|
|
1211
1030
|
"use strict";
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1031
|
+
ANTIGRAVITY_CONFIG = path6.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
|
|
1032
|
+
CLAUDE_CONFIG = path6.join(os.homedir(), ".config/claude/claude_desktop_config.json");
|
|
1033
|
+
VSCODE_GLOBAL_CONFIG = path6.join(os.homedir(), ".config/Code/User/settings.json");
|
|
1034
|
+
OPENCODE_CONFIG = path6.join(os.homedir(), ".config/opencode/opencode.json");
|
|
1215
1035
|
}
|
|
1216
1036
|
});
|
|
1217
1037
|
|
|
1218
|
-
// src/commands/wizard/setup-
|
|
1219
|
-
import
|
|
1220
|
-
import
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
const agentCoreDir = getAgentCoreDir();
|
|
1234
|
-
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
1235
|
-
copyDirToAllStoragePaths(path10.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
1236
|
-
copyDirToAllStoragePaths(path10.join(agentCoreDir, "prompts"), "prompts", dataPaths);
|
|
1237
|
-
if (config.storageMode === "workspace") {
|
|
1238
|
-
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
1239
|
-
if (config.tools.includes("copilot")) {
|
|
1240
|
-
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
1241
|
-
ensureDir(copilotPath);
|
|
1242
|
-
copyPromptsToDir(prompts, copilotPath, ".agent.md");
|
|
1243
|
-
}
|
|
1244
|
-
if (config.tools.includes("antigravity")) {
|
|
1245
|
-
const antigravityPath = getAgentPromptPath(workspacePath, "antigravity");
|
|
1246
|
-
ensureDir(antigravityPath);
|
|
1247
|
-
copyPromptsToDir(prompts, antigravityPath, ".md");
|
|
1248
|
-
}
|
|
1038
|
+
// src/commands/wizard/setup-prompts.ts
|
|
1039
|
+
import { select as select2, multiselect, confirm, isCancel as isCancel2, cancel } from "@clack/prompts";
|
|
1040
|
+
import pc3 from "picocolors";
|
|
1041
|
+
async function promptStorageMode() {
|
|
1042
|
+
const result = await select2({
|
|
1043
|
+
message: "Where should workflow data be stored?",
|
|
1044
|
+
options: [
|
|
1045
|
+
{ value: "global", label: "Global (~/.rrce-workflow/)", hint: "Cross-project access, clean workspace" },
|
|
1046
|
+
{ value: "workspace", label: "Workspace (.rrce-workflow/)", hint: "Self-contained, version with repo" }
|
|
1047
|
+
],
|
|
1048
|
+
initialValue: "global"
|
|
1049
|
+
});
|
|
1050
|
+
if (isCancel2(result)) {
|
|
1051
|
+
cancel("Setup cancelled.");
|
|
1052
|
+
process.exit(0);
|
|
1249
1053
|
}
|
|
1054
|
+
return result;
|
|
1250
1055
|
}
|
|
1251
|
-
function
|
|
1252
|
-
|
|
1253
|
-
if (
|
|
1254
|
-
|
|
1255
|
-
configPath = path10.join(rrceHome, "workspaces", workspaceName, "config.yaml");
|
|
1256
|
-
} else {
|
|
1257
|
-
configPath = path10.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
1056
|
+
async function promptTools() {
|
|
1057
|
+
const options = [];
|
|
1058
|
+
if (isOpenCodeInstalled()) {
|
|
1059
|
+
options.push({ value: "opencode", label: "OpenCode" });
|
|
1258
1060
|
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
version: 1
|
|
1262
|
-
|
|
1263
|
-
storage:
|
|
1264
|
-
mode: ${config.storageMode}`;
|
|
1265
|
-
if (config.globalPath && config.globalPath !== getDefaultRRCEHome2()) {
|
|
1266
|
-
content += `
|
|
1267
|
-
globalPath: "${config.globalPath}"`;
|
|
1061
|
+
if (isVSCodeInstalled()) {
|
|
1062
|
+
options.push({ value: "copilot", label: "GitHub Copilot", hint: "VSCode" });
|
|
1268
1063
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
project:
|
|
1272
|
-
name: "${workspaceName}"
|
|
1273
|
-
sourcePath: "${workspacePath}"
|
|
1274
|
-
|
|
1275
|
-
tools:
|
|
1276
|
-
copilot: ${config.storageMode === "workspace" && config.tools.includes("copilot")}
|
|
1277
|
-
antigravity: ${config.storageMode === "workspace" && config.tools.includes("antigravity")}
|
|
1278
|
-
`;
|
|
1279
|
-
if (config.enableRAG) {
|
|
1280
|
-
content += `
|
|
1281
|
-
semantic_search:
|
|
1282
|
-
enabled: true
|
|
1283
|
-
`;
|
|
1064
|
+
if (isAntigravityInstalled()) {
|
|
1065
|
+
options.push({ value: "antigravity", label: "Antigravity IDE" });
|
|
1284
1066
|
}
|
|
1285
|
-
if (
|
|
1286
|
-
|
|
1287
|
-
linked_projects:
|
|
1288
|
-
`;
|
|
1289
|
-
config.linkedProjects.forEach((name) => {
|
|
1290
|
-
content += ` - ${name}
|
|
1291
|
-
`;
|
|
1292
|
-
});
|
|
1067
|
+
if (options.length === 0) {
|
|
1068
|
+
options.push({ value: "none", label: "No supported IDEs detected", hint: "Skip" });
|
|
1293
1069
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
mcpConfig,
|
|
1303
|
-
workspaceName,
|
|
1304
|
-
true,
|
|
1305
|
-
void 0,
|
|
1306
|
-
workspacePath,
|
|
1307
|
-
config.enableRAG ? { enabled: true } : void 0
|
|
1308
|
-
);
|
|
1309
|
-
saveMCPConfig2(mcpConfig);
|
|
1310
|
-
} catch (e) {
|
|
1311
|
-
note2(
|
|
1312
|
-
`${pc4.yellow("\u26A0")} Could not register project with MCP
|
|
1313
|
-
Error: ${e instanceof Error ? e.message : String(e)}
|
|
1314
|
-
|
|
1315
|
-
You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
|
|
1316
|
-
"MCP Registration Warning"
|
|
1317
|
-
);
|
|
1070
|
+
const result = await multiselect({
|
|
1071
|
+
message: "Which AI tools do you use?",
|
|
1072
|
+
options,
|
|
1073
|
+
required: false
|
|
1074
|
+
});
|
|
1075
|
+
if (isCancel2(result)) {
|
|
1076
|
+
cancel("Setup cancelled.");
|
|
1077
|
+
process.exit(0);
|
|
1318
1078
|
}
|
|
1079
|
+
return result.filter((t) => t !== "none");
|
|
1319
1080
|
}
|
|
1320
|
-
function
|
|
1321
|
-
const
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
default:
|
|
1329
|
-
return [globalPath];
|
|
1081
|
+
async function promptMCPExposure() {
|
|
1082
|
+
const result = await confirm({
|
|
1083
|
+
message: "Expose this project to MCP (AI Agent) server?",
|
|
1084
|
+
initialValue: true
|
|
1085
|
+
});
|
|
1086
|
+
if (isCancel2(result)) {
|
|
1087
|
+
cancel("Setup cancelled.");
|
|
1088
|
+
process.exit(0);
|
|
1330
1089
|
}
|
|
1090
|
+
return result;
|
|
1331
1091
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1092
|
+
async function promptLinkedProjects(existingProjects) {
|
|
1093
|
+
if (existingProjects.length === 0) {
|
|
1094
|
+
return [];
|
|
1095
|
+
}
|
|
1096
|
+
const result = await multiselect({
|
|
1097
|
+
message: "Link knowledge from other projects?",
|
|
1098
|
+
options: existingProjects.map((project) => ({
|
|
1099
|
+
value: `${project.name}:${project.source}`,
|
|
1100
|
+
label: `${project.name} ${pc3.dim(`(${project.source})`)}`,
|
|
1101
|
+
hint: pc3.dim(
|
|
1102
|
+
project.source === "global" ? `~/.rrce-workflow/workspaces/${project.name}` : project.dataPath
|
|
1103
|
+
)
|
|
1104
|
+
})),
|
|
1105
|
+
required: false
|
|
1106
|
+
});
|
|
1107
|
+
if (isCancel2(result)) {
|
|
1108
|
+
cancel("Setup cancelled.");
|
|
1109
|
+
process.exit(0);
|
|
1110
|
+
}
|
|
1111
|
+
return result;
|
|
1112
|
+
}
|
|
1113
|
+
async function promptGitignore() {
|
|
1114
|
+
const result = await confirm({
|
|
1115
|
+
message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
|
|
1116
|
+
initialValue: false
|
|
1117
|
+
});
|
|
1118
|
+
if (isCancel2(result)) {
|
|
1119
|
+
cancel("Setup cancelled.");
|
|
1120
|
+
process.exit(0);
|
|
1121
|
+
}
|
|
1122
|
+
return result;
|
|
1123
|
+
}
|
|
1124
|
+
async function promptRAG() {
|
|
1125
|
+
const result = await confirm({
|
|
1126
|
+
message: `Enable Semantic Search (Local Mini RAG)?
|
|
1127
|
+
${pc3.yellow("\u26A0 First use will download a ~100MB model")}`,
|
|
1128
|
+
initialValue: true
|
|
1129
|
+
});
|
|
1130
|
+
if (isCancel2(result)) {
|
|
1131
|
+
cancel("Setup cancelled.");
|
|
1132
|
+
process.exit(0);
|
|
1133
|
+
}
|
|
1134
|
+
return result;
|
|
1135
|
+
}
|
|
1136
|
+
async function promptConfirmation() {
|
|
1137
|
+
const result = await confirm({
|
|
1138
|
+
message: "Create configuration?",
|
|
1139
|
+
initialValue: true
|
|
1140
|
+
});
|
|
1141
|
+
if (isCancel2(result)) {
|
|
1142
|
+
cancel("Setup cancelled.");
|
|
1143
|
+
process.exit(0);
|
|
1144
|
+
}
|
|
1145
|
+
return result;
|
|
1146
|
+
}
|
|
1147
|
+
var init_setup_prompts = __esm({
|
|
1148
|
+
"src/commands/wizard/setup-prompts.ts"() {
|
|
1334
1149
|
"use strict";
|
|
1335
|
-
|
|
1336
|
-
init_prompts();
|
|
1337
|
-
init_utils();
|
|
1338
|
-
init_vscode();
|
|
1150
|
+
init_install();
|
|
1339
1151
|
}
|
|
1340
1152
|
});
|
|
1341
1153
|
|
|
1342
|
-
// src/
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1154
|
+
// src/types/prompt.ts
|
|
1155
|
+
import { z } from "zod";
|
|
1156
|
+
var PromptArgSchema, AutoIdentitySchema, PromptFrontmatterSchema;
|
|
1157
|
+
var init_prompt = __esm({
|
|
1158
|
+
"src/types/prompt.ts"() {
|
|
1159
|
+
"use strict";
|
|
1160
|
+
PromptArgSchema = z.object({
|
|
1161
|
+
name: z.string(),
|
|
1162
|
+
default: z.string().optional(),
|
|
1163
|
+
prompt: z.string().optional()
|
|
1164
|
+
});
|
|
1165
|
+
AutoIdentitySchema = z.object({
|
|
1166
|
+
user: z.string(),
|
|
1167
|
+
model: z.string()
|
|
1168
|
+
});
|
|
1169
|
+
PromptFrontmatterSchema = z.object({
|
|
1170
|
+
name: z.string(),
|
|
1171
|
+
description: z.string(),
|
|
1172
|
+
"argument-hint": z.union([z.string(), z.array(z.string())]).optional(),
|
|
1173
|
+
tools: z.array(z.string()).optional(),
|
|
1174
|
+
"required-args": z.array(PromptArgSchema).optional(),
|
|
1175
|
+
"optional-args": z.array(PromptArgSchema).optional(),
|
|
1176
|
+
"auto-identity": AutoIdentitySchema.optional()
|
|
1177
|
+
});
|
|
1357
1178
|
}
|
|
1358
|
-
|
|
1359
|
-
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
// src/lib/prompts.ts
|
|
1182
|
+
import * as fs6 from "fs";
|
|
1183
|
+
import * as path7 from "path";
|
|
1184
|
+
import { fileURLToPath } from "url";
|
|
1185
|
+
import matter from "gray-matter";
|
|
1186
|
+
function parsePromptFile(filePath) {
|
|
1187
|
+
try {
|
|
1188
|
+
const fileContent = fs6.readFileSync(filePath, "utf-8");
|
|
1189
|
+
const { data, content } = matter(fileContent);
|
|
1190
|
+
const parsed = PromptFrontmatterSchema.safeParse(data);
|
|
1191
|
+
if (!parsed.success) {
|
|
1192
|
+
console.error(`Failed to parse frontmatter in ${filePath}:`, parsed.error);
|
|
1193
|
+
return null;
|
|
1194
|
+
}
|
|
1195
|
+
return {
|
|
1196
|
+
frontmatter: parsed.data,
|
|
1197
|
+
content: content.trim(),
|
|
1198
|
+
filePath
|
|
1199
|
+
};
|
|
1200
|
+
} catch (error) {
|
|
1201
|
+
console.error(`Error reading prompt file ${filePath}:`, error);
|
|
1202
|
+
return null;
|
|
1360
1203
|
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1204
|
+
}
|
|
1205
|
+
function loadPromptsFromDir(dirPath) {
|
|
1206
|
+
if (!fs6.existsSync(dirPath)) {
|
|
1207
|
+
return [];
|
|
1364
1208
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1209
|
+
const files = fs6.readdirSync(dirPath).filter((f) => f.endsWith(".md"));
|
|
1210
|
+
const prompts = [];
|
|
1211
|
+
for (const file of files) {
|
|
1212
|
+
const prompt = parsePromptFile(path7.join(dirPath, file));
|
|
1213
|
+
if (prompt) {
|
|
1214
|
+
prompts.push(prompt);
|
|
1215
|
+
}
|
|
1368
1216
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1217
|
+
return prompts;
|
|
1218
|
+
}
|
|
1219
|
+
function getAgentCoreDir() {
|
|
1220
|
+
if (__dirname.includes("/src/") || __dirname.includes("\\src\\")) {
|
|
1221
|
+
if (fs6.existsSync(path7.join(process.cwd(), "agent-core"))) {
|
|
1222
|
+
return path7.join(process.cwd(), "agent-core");
|
|
1223
|
+
}
|
|
1224
|
+
return path7.resolve(__dirname, "../..", "agent-core");
|
|
1372
1225
|
}
|
|
1373
|
-
|
|
1374
|
-
${sectionMarker}
|
|
1375
|
-
# Uncomment the following lines if you want to ignore rrce-workflow generated files:
|
|
1376
|
-
${entries.map((e) => `# ${e}`).join("\n")}
|
|
1377
|
-
`;
|
|
1378
|
-
const updatedContent = existingContent.trimEnd() + newSection;
|
|
1379
|
-
fs10.writeFileSync(gitignorePath, updatedContent);
|
|
1380
|
-
return true;
|
|
1226
|
+
return path7.join(__dirname, "..", "agent-core");
|
|
1381
1227
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1228
|
+
function getAgentCorePromptsDir() {
|
|
1229
|
+
return path7.join(getAgentCoreDir(), "prompts");
|
|
1230
|
+
}
|
|
1231
|
+
var __filename, __dirname;
|
|
1232
|
+
var init_prompts = __esm({
|
|
1233
|
+
"src/lib/prompts.ts"() {
|
|
1384
1234
|
"use strict";
|
|
1235
|
+
init_prompt();
|
|
1236
|
+
__filename = fileURLToPath(import.meta.url);
|
|
1237
|
+
__dirname = path7.dirname(__filename);
|
|
1385
1238
|
}
|
|
1386
1239
|
});
|
|
1387
1240
|
|
|
1388
|
-
// src/
|
|
1389
|
-
import * as
|
|
1390
|
-
import * as
|
|
1391
|
-
function
|
|
1392
|
-
const
|
|
1393
|
-
|
|
1394
|
-
|
|
1241
|
+
// src/commands/wizard/utils.ts
|
|
1242
|
+
import * as fs7 from "fs";
|
|
1243
|
+
import * as path8 from "path";
|
|
1244
|
+
function copyPromptsToDir(prompts, targetDir, extension) {
|
|
1245
|
+
for (const prompt of prompts) {
|
|
1246
|
+
const baseName = path8.basename(prompt.filePath, ".md");
|
|
1247
|
+
const targetName = baseName + extension;
|
|
1248
|
+
const targetPath = path8.join(targetDir, targetName);
|
|
1249
|
+
const content = fs7.readFileSync(prompt.filePath, "utf-8");
|
|
1250
|
+
fs7.writeFileSync(targetPath, content);
|
|
1251
|
+
}
|
|
1395
1252
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1253
|
+
function copyDirRecursive(src, dest) {
|
|
1254
|
+
const entries = fs7.readdirSync(src, { withFileTypes: true });
|
|
1255
|
+
for (const entry of entries) {
|
|
1256
|
+
const srcPath = path8.join(src, entry.name);
|
|
1257
|
+
const destPath = path8.join(dest, entry.name);
|
|
1258
|
+
if (entry.isDirectory()) {
|
|
1259
|
+
ensureDir(destPath);
|
|
1260
|
+
copyDirRecursive(srcPath, destPath);
|
|
1261
|
+
} else {
|
|
1262
|
+
fs7.copyFileSync(srcPath, destPath);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
var init_utils = __esm({
|
|
1267
|
+
"src/commands/wizard/utils.ts"() {
|
|
1399
1268
|
"use strict";
|
|
1400
1269
|
init_paths();
|
|
1401
|
-
Logger = class {
|
|
1402
|
-
logPath;
|
|
1403
|
-
constructor() {
|
|
1404
|
-
this.logPath = getLogFilePath();
|
|
1405
|
-
}
|
|
1406
|
-
write(level, message, data) {
|
|
1407
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1408
|
-
let logMessage = `[${timestamp}] [${level}] ${message}`;
|
|
1409
|
-
if (data) {
|
|
1410
|
-
if (data instanceof Error) {
|
|
1411
|
-
logMessage += `
|
|
1412
|
-
${data.stack || data.message}`;
|
|
1413
|
-
} else {
|
|
1414
|
-
try {
|
|
1415
|
-
logMessage += `
|
|
1416
|
-
${JSON.stringify(data, null, 2)}`;
|
|
1417
|
-
} catch (e) {
|
|
1418
|
-
logMessage += `
|
|
1419
|
-
[Circular or invalid data]`;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
logMessage += "\n";
|
|
1424
|
-
try {
|
|
1425
|
-
const dir = path12.dirname(this.logPath);
|
|
1426
|
-
if (!fs11.existsSync(dir)) {
|
|
1427
|
-
fs11.mkdirSync(dir, { recursive: true });
|
|
1428
|
-
}
|
|
1429
|
-
fs11.appendFileSync(this.logPath, logMessage);
|
|
1430
|
-
} catch (e) {
|
|
1431
|
-
console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
|
|
1432
|
-
console.error(logMessage);
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
info(message, data) {
|
|
1436
|
-
this.write("INFO", message, data);
|
|
1437
|
-
}
|
|
1438
|
-
error(message, error) {
|
|
1439
|
-
this.write("ERROR", message, error);
|
|
1440
|
-
}
|
|
1441
|
-
warn(message, data) {
|
|
1442
|
-
this.write("WARN", message, data);
|
|
1443
|
-
}
|
|
1444
|
-
debug(message, data) {
|
|
1445
|
-
this.write("DEBUG", message, data);
|
|
1446
|
-
}
|
|
1447
|
-
};
|
|
1448
|
-
logger = new Logger();
|
|
1449
1270
|
}
|
|
1450
1271
|
});
|
|
1451
1272
|
|
|
1452
|
-
// src/
|
|
1453
|
-
import * as
|
|
1454
|
-
import * as
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
}
|
|
1500
|
-
})();
|
|
1501
|
-
return _RAGService.loadPromise;
|
|
1502
|
-
}
|
|
1503
|
-
/**
|
|
1504
|
-
* Load index from disk
|
|
1505
|
-
*/
|
|
1506
|
-
loadIndex() {
|
|
1507
|
-
if (this.index) return;
|
|
1508
|
-
if (fs12.existsSync(this.indexPath)) {
|
|
1509
|
-
try {
|
|
1510
|
-
const data = fs12.readFileSync(this.indexPath, "utf-8");
|
|
1511
|
-
this.index = JSON.parse(data);
|
|
1512
|
-
logger.info(`RAG: Loaded index from ${this.indexPath} with ${this.index?.chunks.length} chunks.`);
|
|
1513
|
-
} catch (error) {
|
|
1514
|
-
logger.error(`RAG: Failed to load index from ${this.indexPath}`, error);
|
|
1515
|
-
this.index = {
|
|
1516
|
-
version: INDEX_VERSION,
|
|
1517
|
-
baseModel: this.modelName,
|
|
1518
|
-
chunks: []
|
|
1519
|
-
};
|
|
1520
|
-
}
|
|
1521
|
-
} else {
|
|
1522
|
-
this.index = {
|
|
1523
|
-
version: INDEX_VERSION,
|
|
1524
|
-
baseModel: this.modelName,
|
|
1525
|
-
chunks: []
|
|
1526
|
-
};
|
|
1527
|
-
logger.info(`RAG: Created new empty index at ${this.indexPath}`);
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
/**
|
|
1531
|
-
* Save index to disk
|
|
1532
|
-
*/
|
|
1533
|
-
saveIndex() {
|
|
1534
|
-
if (!this.index) return;
|
|
1535
|
-
try {
|
|
1536
|
-
const dir = path13.dirname(this.indexPath);
|
|
1537
|
-
if (!fs12.existsSync(dir)) {
|
|
1538
|
-
fs12.mkdirSync(dir, { recursive: true });
|
|
1539
|
-
}
|
|
1540
|
-
fs12.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
|
|
1541
|
-
logger.info(`RAG: Saved index to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
|
|
1542
|
-
} catch (error) {
|
|
1543
|
-
logger.error(`RAG: Failed to save index to ${this.indexPath}`, error);
|
|
1544
|
-
}
|
|
1273
|
+
// src/commands/wizard/vscode.ts
|
|
1274
|
+
import * as fs8 from "fs";
|
|
1275
|
+
import * as path9 from "path";
|
|
1276
|
+
function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
1277
|
+
const workspaceFilePath = path9.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
1278
|
+
let workspace;
|
|
1279
|
+
if (fs8.existsSync(workspaceFilePath)) {
|
|
1280
|
+
try {
|
|
1281
|
+
const content = fs8.readFileSync(workspaceFilePath, "utf-8");
|
|
1282
|
+
workspace = JSON.parse(content);
|
|
1283
|
+
} catch {
|
|
1284
|
+
workspace = { folders: [], settings: {} };
|
|
1285
|
+
}
|
|
1286
|
+
} else {
|
|
1287
|
+
workspace = { folders: [], settings: {} };
|
|
1288
|
+
}
|
|
1289
|
+
if (!workspace.settings) {
|
|
1290
|
+
workspace.settings = {};
|
|
1291
|
+
}
|
|
1292
|
+
workspace.folders = workspace.folders.filter(
|
|
1293
|
+
(f) => f.path === "." || !f.name?.startsWith("\u{1F4C1}") && !f.name?.startsWith("\u{1F4DA}") && !f.name?.startsWith("\u{1F4CE}") && !f.name?.startsWith("\u{1F4CB}")
|
|
1294
|
+
);
|
|
1295
|
+
const mainFolderIndex = workspace.folders.findIndex((f) => f.path === ".");
|
|
1296
|
+
if (mainFolderIndex === -1) {
|
|
1297
|
+
workspace.folders.unshift({
|
|
1298
|
+
path: ".",
|
|
1299
|
+
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
1300
|
+
});
|
|
1301
|
+
} else {
|
|
1302
|
+
workspace.folders[mainFolderIndex] = {
|
|
1303
|
+
path: ".",
|
|
1304
|
+
name: `\u{1F3E0} ${workspaceName} (workspace)`
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
const referenceFolderPaths = [];
|
|
1308
|
+
const isDetectedProjects = linkedProjects.length > 0 && typeof linkedProjects[0] === "object";
|
|
1309
|
+
if (isDetectedProjects) {
|
|
1310
|
+
const projects = linkedProjects;
|
|
1311
|
+
for (const project of projects) {
|
|
1312
|
+
const sourceLabel = project.source === "global" ? "global" : "local";
|
|
1313
|
+
const folderPath = project.dataPath;
|
|
1314
|
+
if (fs8.existsSync(folderPath)) {
|
|
1315
|
+
referenceFolderPaths.push(folderPath);
|
|
1316
|
+
workspace.folders.push({
|
|
1317
|
+
path: folderPath,
|
|
1318
|
+
name: `\u{1F4C1} ${project.name} [${sourceLabel}]`
|
|
1319
|
+
});
|
|
1545
1320
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
}
|
|
1321
|
+
}
|
|
1322
|
+
} else {
|
|
1323
|
+
const projectNames = linkedProjects;
|
|
1324
|
+
const rrceHome = customGlobalPath || getRRCEHome();
|
|
1325
|
+
for (const projectName of projectNames) {
|
|
1326
|
+
const folderPath = path9.join(rrceHome, "workspaces", projectName);
|
|
1327
|
+
if (fs8.existsSync(folderPath)) {
|
|
1328
|
+
referenceFolderPaths.push(folderPath);
|
|
1329
|
+
workspace.folders.push({
|
|
1330
|
+
path: folderPath,
|
|
1331
|
+
name: `\u{1F4C1} ${projectName} [global]`
|
|
1332
|
+
});
|
|
1558
1333
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
}
|
|
1572
|
-
if (mtime !== void 0 && this.index.fileMetadata[filePath]) {
|
|
1573
|
-
const existingMeta = this.index.fileMetadata[filePath];
|
|
1574
|
-
if (existingMeta.mtime === mtime) {
|
|
1575
|
-
logger.debug(`RAG: Skipping unchanged file ${filePath}`);
|
|
1576
|
-
return false;
|
|
1577
|
-
}
|
|
1578
|
-
}
|
|
1579
|
-
logger.info(`RAG: Indexing file ${filePath}`);
|
|
1580
|
-
this.index.chunks = this.index.chunks.filter((c) => c.filePath !== filePath);
|
|
1581
|
-
const chunks = this.chunkContent(content);
|
|
1582
|
-
for (const chunkText of chunks) {
|
|
1583
|
-
const embedding = await this.generateEmbedding(chunkText);
|
|
1584
|
-
this.index.chunks.push({
|
|
1585
|
-
id: `${filePath}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
1586
|
-
filePath,
|
|
1587
|
-
content: chunkText,
|
|
1588
|
-
embedding,
|
|
1589
|
-
mtime
|
|
1590
|
-
});
|
|
1591
|
-
}
|
|
1592
|
-
this.index.fileMetadata[filePath] = {
|
|
1593
|
-
mtime: mtime ?? Date.now(),
|
|
1594
|
-
chunkCount: chunks.length
|
|
1595
|
-
};
|
|
1596
|
-
this.saveIndex();
|
|
1597
|
-
return true;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (referenceFolderPaths.length > 0) {
|
|
1337
|
+
const readonlyPatterns = {};
|
|
1338
|
+
for (const folderPath of referenceFolderPaths) {
|
|
1339
|
+
readonlyPatterns[`${folderPath}/**`] = true;
|
|
1340
|
+
}
|
|
1341
|
+
const existingReadonly = workspace.settings["files.readonlyInclude"] || {};
|
|
1342
|
+
const cleanedReadonly = {};
|
|
1343
|
+
for (const [pattern, value] of Object.entries(existingReadonly)) {
|
|
1344
|
+
if (!pattern.includes(".rrce-workflow") && !pattern.includes("rrce-workflow/workspaces")) {
|
|
1345
|
+
cleanedReadonly[pattern] = value;
|
|
1598
1346
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1347
|
+
}
|
|
1348
|
+
workspace.settings["files.readonlyInclude"] = {
|
|
1349
|
+
...cleanedReadonly,
|
|
1350
|
+
...readonlyPatterns
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
fs8.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
1354
|
+
}
|
|
1355
|
+
var init_vscode = __esm({
|
|
1356
|
+
"src/commands/wizard/vscode.ts"() {
|
|
1357
|
+
"use strict";
|
|
1358
|
+
init_paths();
|
|
1359
|
+
init_detection();
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
// src/mcp/types.ts
|
|
1364
|
+
var DEFAULT_MCP_CONFIG, DEFAULT_PERMISSIONS;
|
|
1365
|
+
var init_types = __esm({
|
|
1366
|
+
"src/mcp/types.ts"() {
|
|
1367
|
+
"use strict";
|
|
1368
|
+
DEFAULT_MCP_CONFIG = {
|
|
1369
|
+
server: {
|
|
1370
|
+
port: 3e3,
|
|
1371
|
+
autoStart: false
|
|
1372
|
+
},
|
|
1373
|
+
projects: [],
|
|
1374
|
+
defaults: {
|
|
1375
|
+
includeNew: true,
|
|
1376
|
+
permissions: {
|
|
1377
|
+
knowledge: true,
|
|
1378
|
+
tasks: true,
|
|
1379
|
+
refs: true
|
|
1613
1380
|
}
|
|
1614
1381
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1382
|
+
};
|
|
1383
|
+
DEFAULT_PERMISSIONS = {
|
|
1384
|
+
knowledge: true,
|
|
1385
|
+
tasks: true,
|
|
1386
|
+
refs: true
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1391
|
+
// src/mcp/config-utils.ts
|
|
1392
|
+
function findProjectConfig(config, identifier) {
|
|
1393
|
+
return config.projects.find((p) => {
|
|
1394
|
+
if (identifier.path && p.path) {
|
|
1395
|
+
return p.path === identifier.path;
|
|
1396
|
+
}
|
|
1397
|
+
if (!identifier.path && !p.path) {
|
|
1398
|
+
return p.name === identifier.name;
|
|
1399
|
+
}
|
|
1400
|
+
if (identifier.path && !p.path) {
|
|
1401
|
+
return p.name === identifier.name;
|
|
1402
|
+
}
|
|
1403
|
+
return false;
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
var init_config_utils = __esm({
|
|
1407
|
+
"src/mcp/config-utils.ts"() {
|
|
1408
|
+
"use strict";
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
|
|
1412
|
+
// src/mcp/config.ts
|
|
1413
|
+
var config_exports = {};
|
|
1414
|
+
__export(config_exports, {
|
|
1415
|
+
cleanStaleProjects: () => cleanStaleProjects,
|
|
1416
|
+
ensureMCPGlobalPath: () => ensureMCPGlobalPath,
|
|
1417
|
+
getMCPConfigPath: () => getMCPConfigPath,
|
|
1418
|
+
getProjectPermissions: () => getProjectPermissions,
|
|
1419
|
+
isProjectExposed: () => isProjectExposed,
|
|
1420
|
+
loadMCPConfig: () => loadMCPConfig,
|
|
1421
|
+
removeProjectConfig: () => removeProjectConfig,
|
|
1422
|
+
saveMCPConfig: () => saveMCPConfig,
|
|
1423
|
+
setProjectConfig: () => setProjectConfig
|
|
1424
|
+
});
|
|
1425
|
+
import * as fs9 from "fs";
|
|
1426
|
+
import * as path10 from "path";
|
|
1427
|
+
import YAML from "yaml";
|
|
1428
|
+
function getMCPConfigPath() {
|
|
1429
|
+
const workspaceRoot = detectWorkspaceRoot();
|
|
1430
|
+
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1431
|
+
return path10.join(rrceHome, "mcp.yaml");
|
|
1432
|
+
}
|
|
1433
|
+
function ensureMCPGlobalPath() {
|
|
1434
|
+
const workspaceRoot = detectWorkspaceRoot();
|
|
1435
|
+
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1436
|
+
if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
|
|
1437
|
+
const configPath = path10.join(workspaceRoot, ".rrce-workflow", "config.yaml");
|
|
1438
|
+
if (fs9.existsSync(configPath)) {
|
|
1439
|
+
const content = fs9.readFileSync(configPath, "utf-8");
|
|
1440
|
+
const modeMatch = content.match(/mode:\s*(global|workspace)/);
|
|
1441
|
+
if (modeMatch?.[1] === "workspace") {
|
|
1622
1442
|
return {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1443
|
+
configured: false,
|
|
1444
|
+
path: rrceHome,
|
|
1445
|
+
reason: "Workspace mode configured. MCP requires a global storage path."
|
|
1626
1446
|
};
|
|
1627
1447
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
}
|
|
1671
|
-
/**
|
|
1672
|
-
* Basic content chunker
|
|
1673
|
-
*/
|
|
1674
|
-
chunkContent(content, maxChunkSize = 1e3, overlap = 100) {
|
|
1675
|
-
const chunks = [];
|
|
1676
|
-
let start = 0;
|
|
1677
|
-
while (start < content.length) {
|
|
1678
|
-
let end = start + maxChunkSize;
|
|
1679
|
-
if (end >= content.length) {
|
|
1680
|
-
end = content.length;
|
|
1681
|
-
} else {
|
|
1682
|
-
const lastNewline = content.lastIndexOf("\n", end);
|
|
1683
|
-
if (lastNewline > start + maxChunkSize / 2) {
|
|
1684
|
-
end = lastNewline;
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
const chunk = content.substring(start, end).trim();
|
|
1688
|
-
if (chunk.length > 50) {
|
|
1689
|
-
chunks.push(chunk);
|
|
1690
|
-
}
|
|
1691
|
-
if (end === content.length) break;
|
|
1692
|
-
start = end - overlap;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return {
|
|
1451
|
+
configured: true,
|
|
1452
|
+
path: rrceHome
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
function loadMCPConfig() {
|
|
1456
|
+
const configPath = getMCPConfigPath();
|
|
1457
|
+
if (!fs9.existsSync(configPath)) {
|
|
1458
|
+
return { ...DEFAULT_MCP_CONFIG };
|
|
1459
|
+
}
|
|
1460
|
+
try {
|
|
1461
|
+
const content = fs9.readFileSync(configPath, "utf-8");
|
|
1462
|
+
return parseMCPConfig(content);
|
|
1463
|
+
} catch {
|
|
1464
|
+
return { ...DEFAULT_MCP_CONFIG };
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
function saveMCPConfig(config) {
|
|
1468
|
+
const configPath = getMCPConfigPath();
|
|
1469
|
+
const dir = path10.dirname(configPath);
|
|
1470
|
+
if (!fs9.existsSync(dir)) {
|
|
1471
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
1472
|
+
}
|
|
1473
|
+
const content = serializeMCPConfig(config);
|
|
1474
|
+
fs9.writeFileSync(configPath, content);
|
|
1475
|
+
}
|
|
1476
|
+
function parseMCPConfig(content) {
|
|
1477
|
+
try {
|
|
1478
|
+
const parsed = YAML.parse(content);
|
|
1479
|
+
const config = {
|
|
1480
|
+
server: {
|
|
1481
|
+
port: parsed?.server?.port ?? DEFAULT_MCP_CONFIG.server.port,
|
|
1482
|
+
autoStart: parsed?.server?.autoStart ?? DEFAULT_MCP_CONFIG.server.autoStart
|
|
1483
|
+
},
|
|
1484
|
+
defaults: {
|
|
1485
|
+
includeNew: parsed?.defaults?.includeNew ?? DEFAULT_MCP_CONFIG.defaults.includeNew,
|
|
1486
|
+
permissions: {
|
|
1487
|
+
knowledge: parsed?.defaults?.permissions?.knowledge ?? DEFAULT_PERMISSIONS.knowledge,
|
|
1488
|
+
tasks: parsed?.defaults?.permissions?.tasks ?? DEFAULT_PERMISSIONS.tasks,
|
|
1489
|
+
refs: parsed?.defaults?.permissions?.refs ?? DEFAULT_PERMISSIONS.refs
|
|
1693
1490
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1491
|
+
},
|
|
1492
|
+
projects: Array.isArray(parsed?.projects) ? parsed.projects.map((p) => ({
|
|
1493
|
+
name: p.name || "",
|
|
1494
|
+
path: p.path,
|
|
1495
|
+
expose: p.expose ?? true,
|
|
1496
|
+
permissions: {
|
|
1497
|
+
knowledge: p.permissions?.knowledge ?? DEFAULT_PERMISSIONS.knowledge,
|
|
1498
|
+
tasks: p.permissions?.tasks ?? DEFAULT_PERMISSIONS.tasks,
|
|
1499
|
+
refs: p.permissions?.refs ?? DEFAULT_PERMISSIONS.refs
|
|
1500
|
+
},
|
|
1501
|
+
semanticSearch: p.semanticSearch
|
|
1502
|
+
})) : []
|
|
1696
1503
|
};
|
|
1504
|
+
return config;
|
|
1505
|
+
} catch (err) {
|
|
1506
|
+
return { ...DEFAULT_MCP_CONFIG };
|
|
1697
1507
|
}
|
|
1698
|
-
}
|
|
1508
|
+
}
|
|
1509
|
+
function serializeMCPConfig(config) {
|
|
1510
|
+
const header = `# RRCE MCP Hub Configuration
|
|
1511
|
+
# Manages which projects are exposed via MCP
|
|
1699
1512
|
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
const
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
if (fs13.existsSync(path14.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
|
|
1714
|
-
cfgContent = fs13.readFileSync(path14.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
|
|
1715
|
-
} else if (fs13.existsSync(path14.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
|
|
1716
|
-
cfgContent = fs13.readFileSync(path14.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
|
|
1513
|
+
`;
|
|
1514
|
+
return header + YAML.stringify(config, {
|
|
1515
|
+
indent: 2,
|
|
1516
|
+
lineWidth: 0
|
|
1517
|
+
// No line wrapping
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
function setProjectConfig(config, name, expose, permissions, projectPath, semanticSearch) {
|
|
1521
|
+
const existing = findProjectConfig(config, { name, path: projectPath });
|
|
1522
|
+
if (existing) {
|
|
1523
|
+
existing.expose = expose;
|
|
1524
|
+
if (projectPath && !existing.path) {
|
|
1525
|
+
existing.path = projectPath;
|
|
1717
1526
|
}
|
|
1718
|
-
if (
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
const trimmed = line.trim();
|
|
1724
|
-
if (trimmed.startsWith("linked_projects:")) {
|
|
1725
|
-
inLinked = true;
|
|
1726
|
-
continue;
|
|
1727
|
-
}
|
|
1728
|
-
if (inLinked) {
|
|
1729
|
-
if (trimmed.startsWith("-") || trimmed.startsWith("linked_projects")) {
|
|
1730
|
-
} else if (trimmed !== "" && !trimmed.startsWith("#")) {
|
|
1731
|
-
inLinked = false;
|
|
1732
|
-
}
|
|
1733
|
-
if (inLinked && trimmed.startsWith("-")) {
|
|
1734
|
-
const val = trimmed.replace(/^-\s*/, "").trim();
|
|
1735
|
-
const [pName] = val.split(":");
|
|
1736
|
-
if (!globalProjects.some((p) => p.name === pName) && !linkedProjects.some((p) => p.name === pName)) {
|
|
1737
|
-
const found = allProjects.find((p) => p.name === pName);
|
|
1738
|
-
if (found) {
|
|
1739
|
-
linkedProjects.push(found);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1527
|
+
if (permissions) {
|
|
1528
|
+
existing.permissions = { ...existing.permissions, ...permissions };
|
|
1529
|
+
}
|
|
1530
|
+
if (semanticSearch) {
|
|
1531
|
+
existing.semanticSearch = semanticSearch;
|
|
1746
1532
|
}
|
|
1533
|
+
} else {
|
|
1534
|
+
config.projects.push({
|
|
1535
|
+
name,
|
|
1536
|
+
path: projectPath,
|
|
1537
|
+
expose,
|
|
1538
|
+
permissions: permissions ? { ...DEFAULT_PERMISSIONS, ...permissions } : { ...DEFAULT_PERMISSIONS },
|
|
1539
|
+
semanticSearch
|
|
1540
|
+
});
|
|
1747
1541
|
}
|
|
1748
|
-
return
|
|
1749
|
-
}
|
|
1750
|
-
function getRAGIndexPath(project) {
|
|
1751
|
-
const scanRoot = project.path || project.dataPath;
|
|
1752
|
-
return path14.join(project.knowledgePath || path14.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
|
|
1542
|
+
return config;
|
|
1753
1543
|
}
|
|
1754
|
-
function
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
const config = loadMCPConfig();
|
|
1758
|
-
const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
|
|
1759
|
-
const all = projectService.scan({ knownPaths });
|
|
1760
|
-
scanList = all.filter((project) => isProjectExposed(config, project.name, project.dataPath));
|
|
1761
|
-
}
|
|
1762
|
-
return findClosestProject(scanList);
|
|
1544
|
+
function removeProjectConfig(config, name) {
|
|
1545
|
+
config.projects = config.projects.filter((p) => p.name !== name);
|
|
1546
|
+
return config;
|
|
1763
1547
|
}
|
|
1764
|
-
function
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
if (!project) {
|
|
1769
|
-
return null;
|
|
1770
|
-
}
|
|
1771
|
-
const permissions = getProjectPermissions(config, projectName, project.dataPath);
|
|
1772
|
-
if (!permissions.knowledge) {
|
|
1773
|
-
return null;
|
|
1774
|
-
}
|
|
1775
|
-
if (!project.knowledgePath) {
|
|
1776
|
-
return null;
|
|
1777
|
-
}
|
|
1778
|
-
const contextPath = path14.join(project.knowledgePath, "project-context.md");
|
|
1779
|
-
if (!fs13.existsSync(contextPath)) {
|
|
1780
|
-
return null;
|
|
1548
|
+
function isProjectExposed(config, name, projectPath) {
|
|
1549
|
+
const project = findProjectConfig(config, { name, path: projectPath });
|
|
1550
|
+
if (project) {
|
|
1551
|
+
return project.expose;
|
|
1781
1552
|
}
|
|
1782
|
-
return
|
|
1553
|
+
return config.defaults.includeNew;
|
|
1783
1554
|
}
|
|
1784
|
-
function
|
|
1785
|
-
const
|
|
1786
|
-
|
|
1787
|
-
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
|
|
1788
|
-
if (!project) {
|
|
1789
|
-
return [];
|
|
1790
|
-
}
|
|
1791
|
-
const permissions = getProjectPermissions(config, projectName, project.dataPath);
|
|
1792
|
-
if (!permissions.tasks) {
|
|
1793
|
-
return [];
|
|
1794
|
-
}
|
|
1795
|
-
if (!project.tasksPath || !fs13.existsSync(project.tasksPath)) {
|
|
1796
|
-
return [];
|
|
1797
|
-
}
|
|
1798
|
-
const tasks = [];
|
|
1799
|
-
try {
|
|
1800
|
-
const taskDirs = fs13.readdirSync(project.tasksPath, { withFileTypes: true });
|
|
1801
|
-
for (const dir of taskDirs) {
|
|
1802
|
-
if (!dir.isDirectory()) continue;
|
|
1803
|
-
const metaPath = path14.join(project.tasksPath, dir.name, "meta.json");
|
|
1804
|
-
if (fs13.existsSync(metaPath)) {
|
|
1805
|
-
try {
|
|
1806
|
-
const meta = JSON.parse(fs13.readFileSync(metaPath, "utf-8"));
|
|
1807
|
-
tasks.push(meta);
|
|
1808
|
-
} catch {
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
} catch {
|
|
1813
|
-
}
|
|
1814
|
-
return tasks;
|
|
1555
|
+
function getProjectPermissions(config, name, projectPath) {
|
|
1556
|
+
const project = findProjectConfig(config, { name, path: projectPath });
|
|
1557
|
+
return project?.permissions ?? config.defaults.permissions;
|
|
1815
1558
|
}
|
|
1816
|
-
|
|
1817
|
-
const
|
|
1818
|
-
const
|
|
1819
|
-
const
|
|
1820
|
-
const
|
|
1821
|
-
for (const project of projects) {
|
|
1822
|
-
|
|
1823
|
-
if (
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
if (useRAG) {
|
|
1829
|
-
try {
|
|
1830
|
-
const indexPath = path14.join(project.knowledgePath, "embeddings.json");
|
|
1831
|
-
const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
|
|
1832
|
-
const ragResults = await rag.search(query, 5);
|
|
1833
|
-
for (const r of ragResults) {
|
|
1834
|
-
results.push({
|
|
1835
|
-
project: project.name,
|
|
1836
|
-
file: path14.relative(project.knowledgePath, r.filePath),
|
|
1837
|
-
matches: [r.content],
|
|
1838
|
-
// The chunk content is the match
|
|
1839
|
-
score: r.score
|
|
1840
|
-
});
|
|
1841
|
-
}
|
|
1842
|
-
} catch (e) {
|
|
1843
|
-
}
|
|
1844
|
-
continue;
|
|
1559
|
+
function cleanStaleProjects(config) {
|
|
1560
|
+
const rrceHome = getEffectiveGlobalPath();
|
|
1561
|
+
const globalWorkspacesDir = path10.join(rrceHome, "workspaces");
|
|
1562
|
+
const validProjects = [];
|
|
1563
|
+
const removed = [];
|
|
1564
|
+
for (const project of config.projects) {
|
|
1565
|
+
let exists = false;
|
|
1566
|
+
if (project.path) {
|
|
1567
|
+
exists = fs9.existsSync(project.path);
|
|
1568
|
+
} else {
|
|
1569
|
+
const globalPath = path10.join(globalWorkspacesDir, project.name);
|
|
1570
|
+
exists = fs9.existsSync(globalPath);
|
|
1845
1571
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
const filePath = path14.join(project.knowledgePath, file);
|
|
1851
|
-
const content = fs13.readFileSync(filePath, "utf-8");
|
|
1852
|
-
const lines = content.split("\n");
|
|
1853
|
-
const matches = [];
|
|
1854
|
-
for (const line of lines) {
|
|
1855
|
-
if (line.toLowerCase().includes(queryLower)) {
|
|
1856
|
-
matches.push(line.trim());
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
if (matches.length > 0) {
|
|
1860
|
-
results.push({
|
|
1861
|
-
project: project.name,
|
|
1862
|
-
file,
|
|
1863
|
-
matches: matches.slice(0, 5)
|
|
1864
|
-
// Limit to 5 matches per file
|
|
1865
|
-
});
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
} catch {
|
|
1572
|
+
if (exists) {
|
|
1573
|
+
validProjects.push(project);
|
|
1574
|
+
} else {
|
|
1575
|
+
removed.push(project.name);
|
|
1869
1576
|
}
|
|
1870
1577
|
}
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
async function indexKnowledge(projectName, force = false) {
|
|
1874
|
-
const config = loadMCPConfig();
|
|
1875
|
-
const projects = getExposedProjects();
|
|
1876
|
-
const project = projects.find((p) => p.name === projectName || p.path && p.path === projectName);
|
|
1877
|
-
if (!project) {
|
|
1878
|
-
return { success: false, message: `Project '${projectName}' not found`, filesIndexed: 0, filesSkipped: 0 };
|
|
1578
|
+
if (removed.length > 0) {
|
|
1579
|
+
config.projects = validProjects;
|
|
1879
1580
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1581
|
+
return { config, removed };
|
|
1582
|
+
}
|
|
1583
|
+
var init_config = __esm({
|
|
1584
|
+
"src/mcp/config.ts"() {
|
|
1585
|
+
"use strict";
|
|
1586
|
+
init_paths();
|
|
1587
|
+
init_types();
|
|
1588
|
+
init_config_utils();
|
|
1886
1589
|
}
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1590
|
+
});
|
|
1591
|
+
|
|
1592
|
+
// src/commands/wizard/setup-actions.ts
|
|
1593
|
+
import * as fs10 from "fs";
|
|
1594
|
+
import * as path11 from "path";
|
|
1595
|
+
import pc4 from "picocolors";
|
|
1596
|
+
import { note as note2 } from "@clack/prompts";
|
|
1597
|
+
function createDirectoryStructure(dataPaths) {
|
|
1598
|
+
for (const dataPath of dataPaths) {
|
|
1599
|
+
ensureDir(dataPath);
|
|
1600
|
+
ensureDir(path11.join(dataPath, "knowledge"));
|
|
1601
|
+
ensureDir(path11.join(dataPath, "refs"));
|
|
1602
|
+
ensureDir(path11.join(dataPath, "tasks"));
|
|
1603
|
+
ensureDir(path11.join(dataPath, "templates"));
|
|
1890
1604
|
}
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
".cs",
|
|
1910
|
-
".rb",
|
|
1911
|
-
".php",
|
|
1912
|
-
".swift",
|
|
1913
|
-
".md",
|
|
1914
|
-
".mdx",
|
|
1915
|
-
".json",
|
|
1916
|
-
".yaml",
|
|
1917
|
-
".yml",
|
|
1918
|
-
".toml",
|
|
1919
|
-
".sh",
|
|
1920
|
-
".bash",
|
|
1921
|
-
".zsh",
|
|
1922
|
-
".sql",
|
|
1923
|
-
".html",
|
|
1924
|
-
".css",
|
|
1925
|
-
".scss",
|
|
1926
|
-
".sass",
|
|
1927
|
-
".less"
|
|
1928
|
-
];
|
|
1929
|
-
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv", "target", "vendor"];
|
|
1930
|
-
try {
|
|
1931
|
-
const indexPath = path14.join(project.knowledgePath || path14.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
|
|
1932
|
-
const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
|
|
1933
|
-
const rag = new RAGService(indexPath, model);
|
|
1934
|
-
let indexed = 0;
|
|
1935
|
-
let skipped = 0;
|
|
1936
|
-
const scanDir = async (dir) => {
|
|
1937
|
-
const entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
1938
|
-
for (const entry of entries) {
|
|
1939
|
-
const fullPath = path14.join(dir, entry.name);
|
|
1940
|
-
if (entry.isDirectory()) {
|
|
1941
|
-
if (SKIP_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
|
|
1942
|
-
continue;
|
|
1943
|
-
}
|
|
1944
|
-
await scanDir(fullPath);
|
|
1945
|
-
} else if (entry.isFile()) {
|
|
1946
|
-
const ext = path14.extname(entry.name).toLowerCase();
|
|
1947
|
-
if (!INDEXABLE_EXTENSIONS.includes(ext)) {
|
|
1948
|
-
continue;
|
|
1949
|
-
}
|
|
1950
|
-
try {
|
|
1951
|
-
const stat = fs13.statSync(fullPath);
|
|
1952
|
-
const mtime = force ? void 0 : stat.mtimeMs;
|
|
1953
|
-
const content = fs13.readFileSync(fullPath, "utf-8");
|
|
1954
|
-
const wasIndexed = await rag.indexFile(fullPath, content, mtime);
|
|
1955
|
-
if (wasIndexed) {
|
|
1956
|
-
indexed++;
|
|
1957
|
-
} else {
|
|
1958
|
-
skipped++;
|
|
1959
|
-
}
|
|
1960
|
-
} catch (err) {
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
};
|
|
1965
|
-
await scanDir(scanRoot);
|
|
1966
|
-
rag.markFullIndex();
|
|
1967
|
-
const stats = rag.getStats();
|
|
1968
|
-
return {
|
|
1969
|
-
success: true,
|
|
1970
|
-
message: `Indexed ${indexed} files, skipped ${skipped} unchanged. Total: ${stats.totalChunks} chunks from ${stats.totalFiles} files.`,
|
|
1971
|
-
filesIndexed: indexed,
|
|
1972
|
-
filesSkipped: skipped
|
|
1973
|
-
};
|
|
1974
|
-
} catch (error) {
|
|
1975
|
-
return { success: false, message: `Indexing failed: ${error}`, filesIndexed: 0, filesSkipped: 0 };
|
|
1605
|
+
}
|
|
1606
|
+
function installAgentPrompts(config, workspacePath, dataPaths) {
|
|
1607
|
+
const agentCoreDir = getAgentCoreDir();
|
|
1608
|
+
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
1609
|
+
copyDirToAllStoragePaths(path11.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
1610
|
+
copyDirToAllStoragePaths(path11.join(agentCoreDir, "prompts"), "prompts", dataPaths);
|
|
1611
|
+
if (config.storageMode === "workspace") {
|
|
1612
|
+
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
1613
|
+
if (config.tools.includes("copilot")) {
|
|
1614
|
+
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
1615
|
+
ensureDir(copilotPath);
|
|
1616
|
+
copyPromptsToDir(prompts, copilotPath, ".agent.md");
|
|
1617
|
+
}
|
|
1618
|
+
if (config.tools.includes("antigravity")) {
|
|
1619
|
+
const antigravityPath = getAgentPromptPath(workspacePath, "antigravity");
|
|
1620
|
+
ensureDir(antigravityPath);
|
|
1621
|
+
copyPromptsToDir(prompts, antigravityPath, ".md");
|
|
1622
|
+
}
|
|
1976
1623
|
}
|
|
1977
1624
|
}
|
|
1978
|
-
function
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1625
|
+
function createWorkspaceConfig(config, workspacePath, workspaceName) {
|
|
1626
|
+
let configPath;
|
|
1627
|
+
if (config.storageMode === "global") {
|
|
1628
|
+
const rrceHome = config.globalPath || getDefaultRRCEHome2();
|
|
1629
|
+
configPath = path11.join(rrceHome, "workspaces", workspaceName, "config.yaml");
|
|
1630
|
+
} else {
|
|
1631
|
+
configPath = path11.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
1632
|
+
}
|
|
1633
|
+
ensureDir(path11.dirname(configPath));
|
|
1634
|
+
let content = `# RRCE-Workflow Configuration
|
|
1635
|
+
version: 1
|
|
1636
|
+
|
|
1637
|
+
storage:
|
|
1638
|
+
mode: ${config.storageMode}`;
|
|
1639
|
+
if (config.globalPath && config.globalPath !== getDefaultRRCEHome2()) {
|
|
1640
|
+
content += `
|
|
1641
|
+
globalPath: "${config.globalPath}"`;
|
|
1642
|
+
}
|
|
1643
|
+
content += `
|
|
1644
|
+
|
|
1645
|
+
project:
|
|
1646
|
+
name: "${workspaceName}"
|
|
1647
|
+
sourcePath: "${workspacePath}"
|
|
1648
|
+
|
|
1649
|
+
tools:
|
|
1650
|
+
opencode: ${config.tools.includes("opencode")}
|
|
1651
|
+
copilot: ${config.tools.includes("copilot")}
|
|
1652
|
+
antigravity: ${config.tools.includes("antigravity")}
|
|
1988
1653
|
`;
|
|
1989
|
-
if (
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
Please advise the user to do this if they expect to see project context.
|
|
1654
|
+
if (config.enableRAG) {
|
|
1655
|
+
content += `
|
|
1656
|
+
semantic_search:
|
|
1657
|
+
enabled: true
|
|
1994
1658
|
`;
|
|
1995
1659
|
}
|
|
1996
|
-
if (
|
|
1997
|
-
|
|
1998
|
-
|
|
1660
|
+
if (config.linkedProjects.length > 0) {
|
|
1661
|
+
content += `
|
|
1662
|
+
linked_projects:
|
|
1999
1663
|
`;
|
|
2000
|
-
|
|
1664
|
+
config.linkedProjects.forEach((name) => {
|
|
1665
|
+
content += ` - ${name}
|
|
2001
1666
|
`;
|
|
1667
|
+
});
|
|
2002
1668
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
1669
|
+
fs10.writeFileSync(configPath, content);
|
|
1670
|
+
}
|
|
1671
|
+
async function registerWithMCP(config, workspacePath, workspaceName) {
|
|
1672
|
+
if (!config.exposeToMCP) return;
|
|
1673
|
+
try {
|
|
1674
|
+
const { loadMCPConfig: loadMCPConfig3, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1675
|
+
const mcpConfig = loadMCPConfig3();
|
|
1676
|
+
setProjectConfig2(
|
|
1677
|
+
mcpConfig,
|
|
1678
|
+
workspaceName,
|
|
1679
|
+
true,
|
|
1680
|
+
void 0,
|
|
1681
|
+
workspacePath,
|
|
1682
|
+
config.enableRAG ? { enabled: true } : void 0
|
|
1683
|
+
);
|
|
1684
|
+
saveMCPConfig2(mcpConfig);
|
|
1685
|
+
} catch (e) {
|
|
1686
|
+
note2(
|
|
1687
|
+
`${pc4.yellow("\u26A0")} Could not register project with MCP
|
|
1688
|
+
Error: ${e instanceof Error ? e.message : String(e)}
|
|
2005
1689
|
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
1690
|
+
You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
|
|
1691
|
+
"MCP Registration Warning"
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
2009
1694
|
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
1695
|
+
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
1696
|
+
const globalPath = path11.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
|
|
1697
|
+
const workspacePath = path11.join(workspaceRoot, ".rrce-workflow");
|
|
1698
|
+
switch (mode) {
|
|
1699
|
+
case "global":
|
|
1700
|
+
return [globalPath];
|
|
1701
|
+
case "workspace":
|
|
1702
|
+
return [workspacePath];
|
|
1703
|
+
default:
|
|
1704
|
+
return [globalPath];
|
|
2017
1705
|
}
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
const resources = [];
|
|
2031
|
-
resources.push({
|
|
2032
|
-
uri: "rrce://projects",
|
|
2033
|
-
name: "Project List",
|
|
2034
|
-
description: "List of all RRCE projects exposed via MCP",
|
|
2035
|
-
mimeType: "application/json"
|
|
2036
|
-
});
|
|
2037
|
-
for (const project of projects) {
|
|
2038
|
-
const config = loadMCPConfig();
|
|
2039
|
-
const permissions = getProjectPermissions(config, project.name, project.dataPath);
|
|
2040
|
-
if (permissions.knowledge) {
|
|
2041
|
-
resources.push({
|
|
2042
|
-
uri: `rrce://projects/${project.name}/context`,
|
|
2043
|
-
name: `${project.name} - Project Context`,
|
|
2044
|
-
description: `Project context and architecture for ${project.name}`,
|
|
2045
|
-
mimeType: "text/markdown"
|
|
2046
|
-
});
|
|
2047
|
-
}
|
|
2048
|
-
if (permissions.tasks) {
|
|
2049
|
-
resources.push({
|
|
2050
|
-
uri: `rrce://projects/${project.name}/tasks`,
|
|
2051
|
-
name: `${project.name} - Tasks`,
|
|
2052
|
-
description: `Task list and status for ${project.name}`,
|
|
2053
|
-
mimeType: "application/json"
|
|
2054
|
-
});
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
return { resources };
|
|
2058
|
-
});
|
|
2059
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2060
|
-
const { uri } = request.params;
|
|
2061
|
-
logger.info(`Reading resource: ${uri}`);
|
|
1706
|
+
}
|
|
1707
|
+
function installToSelectedIDEs(tools) {
|
|
1708
|
+
const success = [];
|
|
1709
|
+
const failed = [];
|
|
1710
|
+
const toolToTarget = {
|
|
1711
|
+
"opencode": "opencode",
|
|
1712
|
+
"antigravity": "antigravity",
|
|
1713
|
+
"copilot": "vscode-global"
|
|
1714
|
+
};
|
|
1715
|
+
for (const tool of tools) {
|
|
1716
|
+
const target = toolToTarget[tool];
|
|
1717
|
+
if (!target) continue;
|
|
2062
1718
|
try {
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
text: JSON.stringify(projects.map((p) => ({ name: p.name, source: p.source, path: p.path })), null, 2)
|
|
2070
|
-
}]
|
|
2071
|
-
};
|
|
2072
|
-
}
|
|
2073
|
-
const projectMatch = uri.match(/^rrce:\/\/projects\/([^/]+)\/(.+)$/);
|
|
2074
|
-
if (projectMatch && projectMatch[1] && projectMatch[2]) {
|
|
2075
|
-
const projectName = projectMatch[1];
|
|
2076
|
-
const resourceType = projectMatch[2];
|
|
2077
|
-
const content = resourceType === "context" ? getProjectContext(projectName) : JSON.stringify(getProjectTasks(projectName), null, 2);
|
|
2078
|
-
if (content === null) throw new Error(`Resource not found: ${uri}`);
|
|
2079
|
-
return {
|
|
2080
|
-
contents: [{
|
|
2081
|
-
uri,
|
|
2082
|
-
mimeType: resourceType === "tasks" ? "application/json" : "text/markdown",
|
|
2083
|
-
text: content
|
|
2084
|
-
}]
|
|
2085
|
-
};
|
|
1719
|
+
const result = installToConfig(target);
|
|
1720
|
+
const label = getTargetLabel(target);
|
|
1721
|
+
if (result) {
|
|
1722
|
+
success.push(label);
|
|
1723
|
+
} else {
|
|
1724
|
+
failed.push(label);
|
|
2086
1725
|
}
|
|
2087
|
-
throw new Error(`Unknown resource: ${uri}`);
|
|
2088
1726
|
} catch (error) {
|
|
2089
|
-
|
|
2090
|
-
|
|
1727
|
+
const label = getTargetLabel(target);
|
|
1728
|
+
console.error(`Failed to install to ${label}:`, error);
|
|
1729
|
+
failed.push(label);
|
|
2091
1730
|
}
|
|
2092
|
-
}
|
|
1731
|
+
}
|
|
1732
|
+
return { success, failed };
|
|
2093
1733
|
}
|
|
2094
|
-
var
|
|
2095
|
-
"src/
|
|
1734
|
+
var init_setup_actions = __esm({
|
|
1735
|
+
"src/commands/wizard/setup-actions.ts"() {
|
|
2096
1736
|
"use strict";
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
1737
|
+
init_paths();
|
|
1738
|
+
init_prompts();
|
|
1739
|
+
init_utils();
|
|
1740
|
+
init_vscode();
|
|
1741
|
+
init_install();
|
|
2100
1742
|
}
|
|
2101
1743
|
});
|
|
2102
1744
|
|
|
2103
|
-
// src/
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
if (p.frontmatter["optional-args"]) {
|
|
2116
|
-
args.push(...p.frontmatter["optional-args"].map((a) => ({
|
|
2117
|
-
name: a.name,
|
|
2118
|
-
description: a.prompt || a.name,
|
|
2119
|
-
required: false
|
|
2120
|
-
})));
|
|
2121
|
-
}
|
|
2122
|
-
const filename = p.filePath.split("/").pop() || "";
|
|
2123
|
-
const id = filename.replace(/\.md$/, "");
|
|
2124
|
-
return {
|
|
2125
|
-
id,
|
|
2126
|
-
name: p.frontmatter.name,
|
|
2127
|
-
description: p.frontmatter.description,
|
|
2128
|
-
arguments: args,
|
|
2129
|
-
content: p.content
|
|
2130
|
-
};
|
|
2131
|
-
});
|
|
2132
|
-
}
|
|
2133
|
-
function getPromptDef(name) {
|
|
2134
|
-
const all = getAllPrompts();
|
|
2135
|
-
const search = name.toLowerCase();
|
|
2136
|
-
return all.find(
|
|
2137
|
-
(p) => p.name === name || p.id === name || p.name.toLowerCase() === search || p.id.toLowerCase() === search
|
|
2138
|
-
);
|
|
2139
|
-
}
|
|
2140
|
-
function renderPrompt(content, args) {
|
|
2141
|
-
let rendered = content;
|
|
2142
|
-
for (const [key, val] of Object.entries(args)) {
|
|
2143
|
-
rendered = rendered.replace(new RegExp(`{{${key}}}`, "g"), val);
|
|
1745
|
+
// src/commands/wizard/gitignore.ts
|
|
1746
|
+
var gitignore_exports = {};
|
|
1747
|
+
__export(gitignore_exports, {
|
|
1748
|
+
updateGitignore: () => updateGitignore
|
|
1749
|
+
});
|
|
1750
|
+
import * as fs11 from "fs";
|
|
1751
|
+
import * as path12 from "path";
|
|
1752
|
+
function updateGitignore(workspacePath, storageMode, tools) {
|
|
1753
|
+
const gitignorePath = path12.join(workspacePath, ".gitignore");
|
|
1754
|
+
const entries = [];
|
|
1755
|
+
if (storageMode === "workspace") {
|
|
1756
|
+
entries.push(".rrce-workflow/");
|
|
2144
1757
|
}
|
|
2145
|
-
|
|
1758
|
+
if (tools.includes("copilot")) {
|
|
1759
|
+
entries.push(".github/agents/");
|
|
1760
|
+
}
|
|
1761
|
+
if (tools.includes("antigravity")) {
|
|
1762
|
+
entries.push(".agent/workflows/");
|
|
1763
|
+
}
|
|
1764
|
+
entries.push("*.code-workspace");
|
|
1765
|
+
if (entries.length === 0) {
|
|
1766
|
+
return false;
|
|
1767
|
+
}
|
|
1768
|
+
let existingContent = "";
|
|
1769
|
+
if (fs11.existsSync(gitignorePath)) {
|
|
1770
|
+
existingContent = fs11.readFileSync(gitignorePath, "utf-8");
|
|
1771
|
+
}
|
|
1772
|
+
const sectionMarker = "# RRCE-Workflow Generated";
|
|
1773
|
+
if (existingContent.includes(sectionMarker)) {
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
const newSection = `
|
|
1777
|
+
${sectionMarker}
|
|
1778
|
+
# Uncomment the following lines if you want to ignore rrce-workflow generated files:
|
|
1779
|
+
${entries.map((e) => `# ${e}`).join("\n")}
|
|
1780
|
+
`;
|
|
1781
|
+
const updatedContent = existingContent.trimEnd() + newSection;
|
|
1782
|
+
fs11.writeFileSync(gitignorePath, updatedContent);
|
|
1783
|
+
return true;
|
|
2146
1784
|
}
|
|
2147
|
-
var
|
|
2148
|
-
"src/
|
|
1785
|
+
var init_gitignore = __esm({
|
|
1786
|
+
"src/commands/wizard/gitignore.ts"() {
|
|
2149
1787
|
"use strict";
|
|
2150
|
-
init_prompts();
|
|
2151
1788
|
}
|
|
2152
1789
|
});
|
|
2153
1790
|
|
|
2154
|
-
// src/mcp/
|
|
2155
|
-
import "
|
|
2156
|
-
import
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
1791
|
+
// src/mcp/logger.ts
|
|
1792
|
+
import * as fs12 from "fs";
|
|
1793
|
+
import * as path13 from "path";
|
|
1794
|
+
function getLogFilePath() {
|
|
1795
|
+
const workspaceRoot = detectWorkspaceRoot();
|
|
1796
|
+
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1797
|
+
return path13.join(rrceHome, "mcp-server.log");
|
|
1798
|
+
}
|
|
1799
|
+
var Logger, logger;
|
|
1800
|
+
var init_logger = __esm({
|
|
1801
|
+
"src/mcp/logger.ts"() {
|
|
1802
|
+
"use strict";
|
|
1803
|
+
init_paths();
|
|
1804
|
+
Logger = class {
|
|
1805
|
+
logPath;
|
|
1806
|
+
constructor() {
|
|
1807
|
+
this.logPath = getLogFilePath();
|
|
1808
|
+
}
|
|
1809
|
+
write(level, message, data) {
|
|
1810
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1811
|
+
let logMessage = `[${timestamp}] [${level}] ${message}`;
|
|
1812
|
+
if (data) {
|
|
1813
|
+
if (data instanceof Error) {
|
|
1814
|
+
logMessage += `
|
|
1815
|
+
${data.stack || data.message}`;
|
|
1816
|
+
} else {
|
|
1817
|
+
try {
|
|
1818
|
+
logMessage += `
|
|
1819
|
+
${JSON.stringify(data, null, 2)}`;
|
|
1820
|
+
} catch (e) {
|
|
1821
|
+
logMessage += `
|
|
1822
|
+
[Circular or invalid data]`;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
2170
1825
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
required: ["project"]
|
|
1826
|
+
logMessage += "\n";
|
|
1827
|
+
try {
|
|
1828
|
+
const dir = path13.dirname(this.logPath);
|
|
1829
|
+
if (!fs12.existsSync(dir)) {
|
|
1830
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
1831
|
+
}
|
|
1832
|
+
fs12.appendFileSync(this.logPath, logMessage);
|
|
1833
|
+
} catch (e) {
|
|
1834
|
+
console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
|
|
1835
|
+
console.error(logMessage);
|
|
2182
1836
|
}
|
|
2183
|
-
}
|
|
2184
|
-
{
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
1837
|
+
}
|
|
1838
|
+
info(message, data) {
|
|
1839
|
+
this.write("INFO", message, data);
|
|
1840
|
+
}
|
|
1841
|
+
error(message, error) {
|
|
1842
|
+
this.write("ERROR", message, error);
|
|
1843
|
+
}
|
|
1844
|
+
warn(message, data) {
|
|
1845
|
+
this.write("WARN", message, data);
|
|
1846
|
+
}
|
|
1847
|
+
debug(message, data) {
|
|
1848
|
+
this.write("DEBUG", message, data);
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
logger = new Logger();
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
// src/mcp/services/rag.ts
|
|
1856
|
+
import * as fs13 from "fs";
|
|
1857
|
+
import * as path14 from "path";
|
|
1858
|
+
var INDEX_VERSION, DEFAULT_MODEL, RAGService;
|
|
1859
|
+
var init_rag = __esm({
|
|
1860
|
+
"src/mcp/services/rag.ts"() {
|
|
1861
|
+
"use strict";
|
|
1862
|
+
init_logger();
|
|
1863
|
+
INDEX_VERSION = "1.0.0";
|
|
1864
|
+
DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
1865
|
+
RAGService = class _RAGService {
|
|
1866
|
+
// Static cache for the pipeline to prevent reloading model for every instance
|
|
1867
|
+
static pipelineInstance = null;
|
|
1868
|
+
static activeModelName = null;
|
|
1869
|
+
static loadPromise = null;
|
|
1870
|
+
modelName;
|
|
1871
|
+
indexPath;
|
|
1872
|
+
index = null;
|
|
1873
|
+
constructor(indexPath, modelName = DEFAULT_MODEL) {
|
|
1874
|
+
this.indexPath = indexPath;
|
|
1875
|
+
this.modelName = modelName;
|
|
1876
|
+
}
|
|
1877
|
+
/**
|
|
1878
|
+
* Lazy load the model (Singleton pattern)
|
|
1879
|
+
*/
|
|
1880
|
+
async getPipeline() {
|
|
1881
|
+
if (_RAGService.activeModelName === this.modelName && _RAGService.pipelineInstance) {
|
|
1882
|
+
return _RAGService.pipelineInstance;
|
|
2196
1883
|
}
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
name: "list_agents",
|
|
2200
|
-
description: "List available agents (e.g. init, plan) and their arguments. Use this to discover which agent to call.",
|
|
2201
|
-
inputSchema: { type: "object", properties: {} }
|
|
2202
|
-
},
|
|
2203
|
-
{
|
|
2204
|
-
name: "get_agent_prompt",
|
|
2205
|
-
description: 'Get the system prompt for a specific agent. Accepts agent Name (e.g. "RRCE Init") or ID (e.g. "init").',
|
|
2206
|
-
inputSchema: {
|
|
2207
|
-
type: "object",
|
|
2208
|
-
properties: {
|
|
2209
|
-
agent: { type: "string", description: "Name of the agent (e.g. init, plan, execute)" },
|
|
2210
|
-
args: { type: "object", description: "Arguments for the agent prompt", additionalProperties: true }
|
|
2211
|
-
},
|
|
2212
|
-
required: ["agent"]
|
|
1884
|
+
if (_RAGService.activeModelName === this.modelName && _RAGService.loadPromise) {
|
|
1885
|
+
return _RAGService.loadPromise;
|
|
2213
1886
|
}
|
|
1887
|
+
logger.info(`RAG: Initializing model ${this.modelName}...`);
|
|
1888
|
+
_RAGService.activeModelName = this.modelName;
|
|
1889
|
+
_RAGService.loadPromise = (async () => {
|
|
1890
|
+
try {
|
|
1891
|
+
const { pipeline } = await import("@xenova/transformers");
|
|
1892
|
+
const pipe = await pipeline("feature-extraction", this.modelName);
|
|
1893
|
+
_RAGService.pipelineInstance = pipe;
|
|
1894
|
+
logger.info(`RAG: Model ${this.modelName} initialized successfully.`);
|
|
1895
|
+
return pipe;
|
|
1896
|
+
} catch (error) {
|
|
1897
|
+
logger.error(`RAG: Failed to initialize model ${this.modelName}`, error);
|
|
1898
|
+
_RAGService.pipelineInstance = null;
|
|
1899
|
+
_RAGService.activeModelName = null;
|
|
1900
|
+
_RAGService.loadPromise = null;
|
|
1901
|
+
throw error;
|
|
1902
|
+
}
|
|
1903
|
+
})();
|
|
1904
|
+
return _RAGService.loadPromise;
|
|
2214
1905
|
}
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
1906
|
+
/**
|
|
1907
|
+
* Load index from disk
|
|
1908
|
+
*/
|
|
1909
|
+
loadIndex() {
|
|
1910
|
+
if (this.index) return;
|
|
1911
|
+
if (fs13.existsSync(this.indexPath)) {
|
|
1912
|
+
try {
|
|
1913
|
+
const data = fs13.readFileSync(this.indexPath, "utf-8");
|
|
1914
|
+
this.index = JSON.parse(data);
|
|
1915
|
+
logger.info(`RAG: Loaded index from ${this.indexPath} with ${this.index?.chunks.length} chunks.`);
|
|
1916
|
+
} catch (error) {
|
|
1917
|
+
logger.error(`RAG: Failed to load index from ${this.indexPath}`, error);
|
|
1918
|
+
this.index = {
|
|
1919
|
+
version: INDEX_VERSION,
|
|
1920
|
+
baseModel: this.modelName,
|
|
1921
|
+
chunks: []
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
} else {
|
|
1925
|
+
this.index = {
|
|
1926
|
+
version: INDEX_VERSION,
|
|
1927
|
+
baseModel: this.modelName,
|
|
1928
|
+
chunks: []
|
|
1929
|
+
};
|
|
1930
|
+
logger.info(`RAG: Created new empty index at ${this.indexPath}`);
|
|
2234
1931
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1934
|
+
* Save index to disk
|
|
1935
|
+
*/
|
|
1936
|
+
saveIndex() {
|
|
1937
|
+
if (!this.index) return;
|
|
1938
|
+
try {
|
|
1939
|
+
const dir = path14.dirname(this.indexPath);
|
|
1940
|
+
if (!fs13.existsSync(dir)) {
|
|
1941
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
1942
|
+
}
|
|
1943
|
+
fs13.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
|
|
1944
|
+
logger.info(`RAG: Saved index to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
|
|
1945
|
+
} catch (error) {
|
|
1946
|
+
logger.error(`RAG: Failed to save index to ${this.indexPath}`, error);
|
|
2239
1947
|
}
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
1948
|
+
}
|
|
1949
|
+
/**
|
|
1950
|
+
* Generate embedding for text
|
|
1951
|
+
*/
|
|
1952
|
+
async generateEmbedding(text2) {
|
|
1953
|
+
const pipe = await this.getPipeline();
|
|
1954
|
+
try {
|
|
1955
|
+
const output = await pipe(text2, { pooling: "mean", normalize: true });
|
|
1956
|
+
return Array.from(output.data);
|
|
1957
|
+
} catch (error) {
|
|
1958
|
+
logger.error("RAG: Error generating embedding", error);
|
|
1959
|
+
throw error;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Index a file (smart: skips if mtime unchanged)
|
|
1964
|
+
* @param filePath Absolute path to the file
|
|
1965
|
+
* @param content File content
|
|
1966
|
+
* @param mtime Optional modification time (if not provided, always re-indexes)
|
|
1967
|
+
* @returns true if file was indexed, false if skipped
|
|
1968
|
+
*/
|
|
1969
|
+
async indexFile(filePath, content, mtime) {
|
|
1970
|
+
this.loadIndex();
|
|
1971
|
+
if (!this.index) throw new Error("Index not initialized");
|
|
1972
|
+
if (!this.index.fileMetadata) {
|
|
1973
|
+
this.index.fileMetadata = {};
|
|
2249
1974
|
}
|
|
2250
|
-
|
|
2251
|
-
const
|
|
2252
|
-
if (
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
Available projects: ${projects}`;
|
|
2256
|
-
logger.warn(msg);
|
|
2257
|
-
return { content: [{ type: "text", text: msg }], isError: true };
|
|
1975
|
+
if (mtime !== void 0 && this.index.fileMetadata[filePath]) {
|
|
1976
|
+
const existingMeta = this.index.fileMetadata[filePath];
|
|
1977
|
+
if (existingMeta.mtime === mtime) {
|
|
1978
|
+
logger.debug(`RAG: Skipping unchanged file ${filePath}`);
|
|
1979
|
+
return false;
|
|
2258
1980
|
}
|
|
2259
|
-
return { content: [{ type: "text", text: context }] };
|
|
2260
1981
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
};
|
|
1982
|
+
logger.info(`RAG: Indexing file ${filePath}`);
|
|
1983
|
+
this.index.chunks = this.index.chunks.filter((c) => c.filePath !== filePath);
|
|
1984
|
+
const chunks = this.chunkContent(content);
|
|
1985
|
+
for (const chunkText of chunks) {
|
|
1986
|
+
const embedding = await this.generateEmbedding(chunkText);
|
|
1987
|
+
this.index.chunks.push({
|
|
1988
|
+
id: `${filePath}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
1989
|
+
filePath,
|
|
1990
|
+
content: chunkText,
|
|
1991
|
+
embedding,
|
|
1992
|
+
mtime
|
|
1993
|
+
});
|
|
2274
1994
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
1995
|
+
this.index.fileMetadata[filePath] = {
|
|
1996
|
+
mtime: mtime ?? Date.now(),
|
|
1997
|
+
chunkCount: chunks.length
|
|
1998
|
+
};
|
|
1999
|
+
this.saveIndex();
|
|
2000
|
+
return true;
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Remove a file from index
|
|
2004
|
+
*/
|
|
2005
|
+
async removeFile(filePath) {
|
|
2006
|
+
this.loadIndex();
|
|
2007
|
+
if (!this.index) return;
|
|
2008
|
+
const initialCount = this.index.chunks.length;
|
|
2009
|
+
this.index.chunks = this.index.chunks.filter((c) => c.filePath !== filePath);
|
|
2010
|
+
if (this.index.fileMetadata) {
|
|
2011
|
+
delete this.index.fileMetadata[filePath];
|
|
2291
2012
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
To fix this:
|
|
2297
|
-
1. Open a terminal.
|
|
2298
|
-
2. Run: npx rrce-workflow mcp configure
|
|
2299
|
-
3. Select the projects you want to expose to the AI.
|
|
2300
|
-
4. Restart the MCP server (or it may pick up changes automatically).
|
|
2301
|
-
`;
|
|
2302
|
-
return { content: [{ type: "text", text: msg }] };
|
|
2013
|
+
if (this.index.chunks.length !== initialCount) {
|
|
2014
|
+
logger.info(`RAG: Removed file ${filePath} from index (${initialCount - this.index.chunks.length} chunks removed)`);
|
|
2015
|
+
this.saveIndex();
|
|
2303
2016
|
}
|
|
2304
|
-
default:
|
|
2305
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
2306
2017
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
}
|
|
2320
|
-
});
|
|
2321
|
-
|
|
2322
|
-
// src/mcp/handlers/prompts.ts
|
|
2323
|
-
import "@modelcontextprotocol/sdk/server/index.js";
|
|
2324
|
-
import {
|
|
2325
|
-
ListPromptsRequestSchema,
|
|
2326
|
-
GetPromptRequestSchema
|
|
2327
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
2328
|
-
import * as path15 from "path";
|
|
2329
|
-
function registerPromptHandlers(server) {
|
|
2330
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
2331
|
-
logger.debug("Listing prompts");
|
|
2332
|
-
const prompts = getAllPrompts();
|
|
2333
|
-
return {
|
|
2334
|
-
prompts: prompts.map((p) => ({
|
|
2335
|
-
name: p.name,
|
|
2336
|
-
description: p.description,
|
|
2337
|
-
arguments: p.arguments.map((a) => ({
|
|
2338
|
-
name: a.name,
|
|
2339
|
-
description: a.description,
|
|
2340
|
-
required: a.required
|
|
2341
|
-
}))
|
|
2342
|
-
}))
|
|
2343
|
-
};
|
|
2344
|
-
});
|
|
2345
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
2346
|
-
const { name, arguments: args } = request.params;
|
|
2347
|
-
logger.info(`Getting prompt: ${name}`, args);
|
|
2348
|
-
const promptDef = getPromptDef(name);
|
|
2349
|
-
if (!promptDef) {
|
|
2350
|
-
logger.error(`Prompt not found: ${name}`);
|
|
2351
|
-
throw new Error(`Prompt not found: ${name}`);
|
|
2352
|
-
}
|
|
2353
|
-
try {
|
|
2354
|
-
const providedArgs = args || {};
|
|
2355
|
-
const missingArgs = promptDef.arguments.filter((a) => a.required && !providedArgs[a.name]).map((a) => a.name);
|
|
2356
|
-
if (missingArgs.length > 0) {
|
|
2357
|
-
throw new Error(`Missing required arguments: ${missingArgs.join(", ")}`);
|
|
2018
|
+
/**
|
|
2019
|
+
* Get index statistics
|
|
2020
|
+
*/
|
|
2021
|
+
getStats() {
|
|
2022
|
+
this.loadIndex();
|
|
2023
|
+
if (!this.index) return { totalChunks: 0, totalFiles: 0 };
|
|
2024
|
+
const fileCount = this.index.fileMetadata ? Object.keys(this.index.fileMetadata).length : 0;
|
|
2025
|
+
return {
|
|
2026
|
+
totalChunks: this.index.chunks.length,
|
|
2027
|
+
totalFiles: fileCount,
|
|
2028
|
+
lastFullIndex: this.index.lastFullIndex
|
|
2029
|
+
};
|
|
2358
2030
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2031
|
+
/**
|
|
2032
|
+
* Mark the last full index timestamp
|
|
2033
|
+
*/
|
|
2034
|
+
markFullIndex() {
|
|
2035
|
+
this.loadIndex();
|
|
2036
|
+
if (!this.index) return;
|
|
2037
|
+
this.index.lastFullIndex = Date.now();
|
|
2038
|
+
this.saveIndex();
|
|
2362
2039
|
}
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2040
|
+
/**
|
|
2041
|
+
* Search the index
|
|
2042
|
+
*/
|
|
2043
|
+
async search(query, limit = 5) {
|
|
2044
|
+
this.loadIndex();
|
|
2045
|
+
if (!this.index || this.index.chunks.length === 0) {
|
|
2046
|
+
logger.warn("RAG: Search called on empty index");
|
|
2047
|
+
return [];
|
|
2048
|
+
}
|
|
2049
|
+
logger.info(`RAG: Searching for "${query}" (limit: ${limit})`);
|
|
2050
|
+
const queryEmbedding = await this.generateEmbedding(query);
|
|
2051
|
+
const results = this.index.chunks.map((chunk) => {
|
|
2052
|
+
const score = this.cosineSimilarity(queryEmbedding, chunk.embedding);
|
|
2053
|
+
return { ...chunk, score };
|
|
2054
|
+
});
|
|
2055
|
+
results.sort((a, b) => b.score - a.score);
|
|
2056
|
+
const topResults = results.slice(0, limit);
|
|
2057
|
+
logger.info(`RAG: Search returned ${topResults.length} matches. Top score: ${topResults[0]?.score.toFixed(4)}`);
|
|
2058
|
+
return topResults;
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Simple cosine similarity
|
|
2062
|
+
*/
|
|
2063
|
+
cosineSimilarity(a, b) {
|
|
2064
|
+
let dotProduct = 0;
|
|
2065
|
+
let normA = 0;
|
|
2066
|
+
let normB = 0;
|
|
2067
|
+
for (let i = 0; i < a.length; i++) {
|
|
2068
|
+
dotProduct += a[i] * b[i];
|
|
2069
|
+
normA += a[i] * a[i];
|
|
2070
|
+
normB += b[i] * b[i];
|
|
2376
2071
|
}
|
|
2072
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
2377
2073
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
logger.error(`Failed to get prompt: ${name}`, error);
|
|
2405
|
-
throw error;
|
|
2406
|
-
}
|
|
2407
|
-
});
|
|
2408
|
-
}
|
|
2409
|
-
var init_prompts3 = __esm({
|
|
2410
|
-
"src/mcp/handlers/prompts.ts"() {
|
|
2411
|
-
"use strict";
|
|
2412
|
-
init_logger();
|
|
2413
|
-
init_resources();
|
|
2414
|
-
init_prompts2();
|
|
2415
|
-
init_paths();
|
|
2074
|
+
/**
|
|
2075
|
+
* Basic content chunker
|
|
2076
|
+
*/
|
|
2077
|
+
chunkContent(content, maxChunkSize = 1e3, overlap = 100) {
|
|
2078
|
+
const chunks = [];
|
|
2079
|
+
let start = 0;
|
|
2080
|
+
while (start < content.length) {
|
|
2081
|
+
let end = start + maxChunkSize;
|
|
2082
|
+
if (end >= content.length) {
|
|
2083
|
+
end = content.length;
|
|
2084
|
+
} else {
|
|
2085
|
+
const lastNewline = content.lastIndexOf("\n", end);
|
|
2086
|
+
if (lastNewline > start + maxChunkSize / 2) {
|
|
2087
|
+
end = lastNewline;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
const chunk = content.substring(start, end).trim();
|
|
2091
|
+
if (chunk.length > 50) {
|
|
2092
|
+
chunks.push(chunk);
|
|
2093
|
+
}
|
|
2094
|
+
if (end === content.length) break;
|
|
2095
|
+
start = end - overlap;
|
|
2096
|
+
}
|
|
2097
|
+
return chunks;
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2416
2100
|
}
|
|
2417
2101
|
});
|
|
2418
2102
|
|
|
2419
|
-
// src/mcp/
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
});
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
})
|
|
2435
|
-
|
|
2436
|
-
logger.error("Unhandled Rejection", reason);
|
|
2437
|
-
console.error("Unhandled Rejection:", reason);
|
|
2438
|
-
});
|
|
2439
|
-
const config = loadMCPConfig();
|
|
2440
|
-
mcpServer = new Server4(
|
|
2441
|
-
{ name: "rrce-mcp-hub", version: "1.0.0" },
|
|
2442
|
-
{ capabilities: { resources: {}, tools: {}, prompts: {} } }
|
|
2443
|
-
);
|
|
2444
|
-
mcpServer.onerror = (error) => {
|
|
2445
|
-
logger.error("MCP Server Error", error);
|
|
2446
|
-
};
|
|
2447
|
-
registerResourceHandlers(mcpServer);
|
|
2448
|
-
registerToolHandlers(mcpServer);
|
|
2449
|
-
registerPromptHandlers(mcpServer);
|
|
2450
|
-
if (!options.interactive) {
|
|
2451
|
-
const transport = new StdioServerTransport();
|
|
2452
|
-
await mcpServer.connect(transport);
|
|
2453
|
-
} else {
|
|
2454
|
-
logger.info("Running in interactive mode (Stdio transport detached)");
|
|
2103
|
+
// src/mcp/resources.ts
|
|
2104
|
+
import * as fs14 from "fs";
|
|
2105
|
+
import * as path15 from "path";
|
|
2106
|
+
function getExposedProjects() {
|
|
2107
|
+
const config = loadMCPConfig();
|
|
2108
|
+
const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
|
|
2109
|
+
const allProjects = projectService.scan({ knownPaths });
|
|
2110
|
+
const globalProjects = allProjects.filter((project) => isProjectExposed(config, project.name, project.dataPath));
|
|
2111
|
+
const activeProject = detectActiveProject(globalProjects);
|
|
2112
|
+
let linkedProjects = [];
|
|
2113
|
+
if (activeProject) {
|
|
2114
|
+
const localConfigPath = path15.join(activeProject.dataPath, "config.yaml");
|
|
2115
|
+
let cfgContent = null;
|
|
2116
|
+
if (fs14.existsSync(path15.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
|
|
2117
|
+
cfgContent = fs14.readFileSync(path15.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
|
|
2118
|
+
} else if (fs14.existsSync(path15.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
|
|
2119
|
+
cfgContent = fs14.readFileSync(path15.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
|
|
2455
2120
|
}
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2121
|
+
if (cfgContent) {
|
|
2122
|
+
if (cfgContent.includes("linked_projects:")) {
|
|
2123
|
+
const lines = cfgContent.split("\n");
|
|
2124
|
+
let inLinked = false;
|
|
2125
|
+
for (const line of lines) {
|
|
2126
|
+
const trimmed = line.trim();
|
|
2127
|
+
if (trimmed.startsWith("linked_projects:")) {
|
|
2128
|
+
inLinked = true;
|
|
2129
|
+
continue;
|
|
2130
|
+
}
|
|
2131
|
+
if (inLinked) {
|
|
2132
|
+
if (trimmed.startsWith("-") || trimmed.startsWith("linked_projects")) {
|
|
2133
|
+
} else if (trimmed !== "" && !trimmed.startsWith("#")) {
|
|
2134
|
+
inLinked = false;
|
|
2135
|
+
}
|
|
2136
|
+
if (inLinked && trimmed.startsWith("-")) {
|
|
2137
|
+
const val = trimmed.replace(/^-\s*/, "").trim();
|
|
2138
|
+
const [pName] = val.split(":");
|
|
2139
|
+
if (!globalProjects.some((p) => p.name === pName) && !linkedProjects.some((p) => p.name === pName)) {
|
|
2140
|
+
const found = allProjects.find((p) => p.name === pName);
|
|
2141
|
+
if (found) {
|
|
2142
|
+
linkedProjects.push(found);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2462
2149
|
}
|
|
2463
|
-
return { port: config.server.port, pid: process.pid };
|
|
2464
|
-
} catch (error) {
|
|
2465
|
-
logger.error("Failed to start MCP server", error);
|
|
2466
|
-
throw error;
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
function stopMCPServer() {
|
|
2470
|
-
if (mcpServer) {
|
|
2471
|
-
logger.info("Stopping MCP Server...");
|
|
2472
|
-
mcpServer.close();
|
|
2473
|
-
mcpServer = null;
|
|
2474
2150
|
}
|
|
2475
|
-
|
|
2476
|
-
logger.info("RRCE MCP Hub stopped");
|
|
2151
|
+
return [...globalProjects, ...linkedProjects];
|
|
2477
2152
|
}
|
|
2478
|
-
function
|
|
2479
|
-
|
|
2153
|
+
function getRAGIndexPath(project) {
|
|
2154
|
+
const scanRoot = project.path || project.dataPath;
|
|
2155
|
+
return path15.join(project.knowledgePath || path15.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
|
|
2480
2156
|
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
init_resources2();
|
|
2489
|
-
init_tools();
|
|
2490
|
-
init_prompts3();
|
|
2491
|
-
serverState = { running: false };
|
|
2492
|
-
mcpServer = null;
|
|
2157
|
+
function detectActiveProject(knownProjects) {
|
|
2158
|
+
let scanList = knownProjects;
|
|
2159
|
+
if (!scanList) {
|
|
2160
|
+
const config = loadMCPConfig();
|
|
2161
|
+
const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
|
|
2162
|
+
const all = projectService.scan({ knownPaths });
|
|
2163
|
+
scanList = all.filter((project) => isProjectExposed(config, project.name, project.dataPath));
|
|
2493
2164
|
}
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
// src/mcp/install.ts
|
|
2497
|
-
import * as fs14 from "fs";
|
|
2498
|
-
import * as path16 from "path";
|
|
2499
|
-
import * as os from "os";
|
|
2500
|
-
function checkInstallStatus(workspacePath) {
|
|
2501
|
-
return {
|
|
2502
|
-
antigravity: checkAntigravityConfig(),
|
|
2503
|
-
claude: checkClaudeConfig(),
|
|
2504
|
-
vscodeGlobal: checkVSCodeGlobalConfig(),
|
|
2505
|
-
vscodeWorkspace: workspacePath ? checkVSCodeWorkspaceConfig(workspacePath) : false,
|
|
2506
|
-
opencode: checkOpenCodeConfig()
|
|
2507
|
-
};
|
|
2165
|
+
return findClosestProject(scanList);
|
|
2508
2166
|
}
|
|
2509
|
-
function
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
return false;
|
|
2167
|
+
function getProjectContext(projectName) {
|
|
2168
|
+
const config = loadMCPConfig();
|
|
2169
|
+
const projects = projectService.scan();
|
|
2170
|
+
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
|
|
2171
|
+
if (!project) {
|
|
2172
|
+
return null;
|
|
2516
2173
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
try {
|
|
2521
|
-
const content = JSON.parse(fs14.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
2522
|
-
return !!content.mcpServers?.["rrce"];
|
|
2523
|
-
} catch {
|
|
2524
|
-
return false;
|
|
2174
|
+
const permissions = getProjectPermissions(config, projectName, project.dataPath);
|
|
2175
|
+
if (!permissions.knowledge) {
|
|
2176
|
+
return null;
|
|
2525
2177
|
}
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
if (!fs14.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
|
|
2529
|
-
try {
|
|
2530
|
-
const content = JSON.parse(fs14.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
2531
|
-
return !!content["mcp.servers"]?.["rrce"];
|
|
2532
|
-
} catch {
|
|
2533
|
-
return false;
|
|
2178
|
+
if (!project.knowledgePath) {
|
|
2179
|
+
return null;
|
|
2534
2180
|
}
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
if (!fs14.existsSync(configPath)) return false;
|
|
2539
|
-
try {
|
|
2540
|
-
const content = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
|
|
2541
|
-
return !!content.servers?.["rrce"];
|
|
2542
|
-
} catch {
|
|
2543
|
-
return false;
|
|
2181
|
+
const contextPath = path15.join(project.knowledgePath, "project-context.md");
|
|
2182
|
+
if (!fs14.existsSync(contextPath)) {
|
|
2183
|
+
return null;
|
|
2544
2184
|
}
|
|
2185
|
+
return fs14.readFileSync(contextPath, "utf-8");
|
|
2545
2186
|
}
|
|
2546
|
-
function
|
|
2547
|
-
|
|
2187
|
+
function getProjectTasks(projectName) {
|
|
2188
|
+
const config = loadMCPConfig();
|
|
2189
|
+
const projects = projectService.scan();
|
|
2190
|
+
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
|
|
2191
|
+
if (!project) {
|
|
2192
|
+
return [];
|
|
2193
|
+
}
|
|
2194
|
+
const permissions = getProjectPermissions(config, projectName, project.dataPath);
|
|
2195
|
+
if (!permissions.tasks) {
|
|
2196
|
+
return [];
|
|
2197
|
+
}
|
|
2198
|
+
if (!project.tasksPath || !fs14.existsSync(project.tasksPath)) {
|
|
2199
|
+
return [];
|
|
2200
|
+
}
|
|
2201
|
+
const tasks = [];
|
|
2548
2202
|
try {
|
|
2549
|
-
const
|
|
2550
|
-
|
|
2203
|
+
const taskDirs = fs14.readdirSync(project.tasksPath, { withFileTypes: true });
|
|
2204
|
+
for (const dir of taskDirs) {
|
|
2205
|
+
if (!dir.isDirectory()) continue;
|
|
2206
|
+
const metaPath = path15.join(project.tasksPath, dir.name, "meta.json");
|
|
2207
|
+
if (fs14.existsSync(metaPath)) {
|
|
2208
|
+
try {
|
|
2209
|
+
const meta = JSON.parse(fs14.readFileSync(metaPath, "utf-8"));
|
|
2210
|
+
tasks.push(meta);
|
|
2211
|
+
} catch {
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2551
2215
|
} catch {
|
|
2552
|
-
return false;
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
function isInstalledAnywhere(workspacePath) {
|
|
2556
|
-
const status = checkInstallStatus(workspacePath);
|
|
2557
|
-
return status.antigravity || status.claude || status.vscodeGlobal || status.vscodeWorkspace || status.opencode;
|
|
2558
|
-
}
|
|
2559
|
-
function installToConfig(target, workspacePath) {
|
|
2560
|
-
switch (target) {
|
|
2561
|
-
case "antigravity":
|
|
2562
|
-
return installToAntigravity();
|
|
2563
|
-
case "claude":
|
|
2564
|
-
return installToClaude();
|
|
2565
|
-
case "vscode-global":
|
|
2566
|
-
return installToVSCodeGlobal();
|
|
2567
|
-
case "vscode-workspace":
|
|
2568
|
-
return workspacePath ? installToVSCodeWorkspace(workspacePath) : false;
|
|
2569
|
-
case "opencode":
|
|
2570
|
-
return installToOpenCode();
|
|
2571
|
-
default:
|
|
2572
|
-
return false;
|
|
2573
2216
|
}
|
|
2217
|
+
return tasks;
|
|
2574
2218
|
}
|
|
2575
|
-
function
|
|
2576
|
-
const
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2219
|
+
async function searchKnowledge(query, projectFilter) {
|
|
2220
|
+
const config = loadMCPConfig();
|
|
2221
|
+
const projects = getExposedProjects();
|
|
2222
|
+
const results = [];
|
|
2223
|
+
const queryLower = query.toLowerCase();
|
|
2224
|
+
for (const project of projects) {
|
|
2225
|
+
if (projectFilter && project.name !== projectFilter) continue;
|
|
2226
|
+
const permissions = getProjectPermissions(config, project.name, project.dataPath);
|
|
2227
|
+
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
2228
|
+
const projConfig = config.projects.find(
|
|
2229
|
+
(p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
|
|
2230
|
+
);
|
|
2231
|
+
const useRAG = projConfig?.semanticSearch?.enabled;
|
|
2232
|
+
if (useRAG) {
|
|
2233
|
+
try {
|
|
2234
|
+
const indexPath = path15.join(project.knowledgePath, "embeddings.json");
|
|
2235
|
+
const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
|
|
2236
|
+
const ragResults = await rag.search(query, 5);
|
|
2237
|
+
for (const r of ragResults) {
|
|
2238
|
+
results.push({
|
|
2239
|
+
project: project.name,
|
|
2240
|
+
file: path15.relative(project.knowledgePath, r.filePath),
|
|
2241
|
+
matches: [r.content],
|
|
2242
|
+
// The chunk content is the match
|
|
2243
|
+
score: r.score
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
} catch (e) {
|
|
2247
|
+
}
|
|
2248
|
+
continue;
|
|
2585
2249
|
}
|
|
2586
|
-
}
|
|
2587
|
-
if (!config.mcpServers) config.mcpServers = {};
|
|
2588
|
-
config.mcpServers["rrce"] = {
|
|
2589
|
-
command: "npx",
|
|
2590
|
-
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
2591
|
-
};
|
|
2592
|
-
try {
|
|
2593
|
-
fs14.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
|
|
2594
|
-
return true;
|
|
2595
|
-
} catch {
|
|
2596
|
-
return false;
|
|
2597
|
-
}
|
|
2598
|
-
}
|
|
2599
|
-
function installToClaude() {
|
|
2600
|
-
const dir = path16.dirname(CLAUDE_CONFIG);
|
|
2601
|
-
if (!fs14.existsSync(dir)) {
|
|
2602
|
-
fs14.mkdirSync(dir, { recursive: true });
|
|
2603
|
-
}
|
|
2604
|
-
let config = { mcpServers: {} };
|
|
2605
|
-
if (fs14.existsSync(CLAUDE_CONFIG)) {
|
|
2606
2250
|
try {
|
|
2607
|
-
|
|
2251
|
+
const files = fs14.readdirSync(project.knowledgePath);
|
|
2252
|
+
for (const file of files) {
|
|
2253
|
+
if (!file.endsWith(".md")) continue;
|
|
2254
|
+
const filePath = path15.join(project.knowledgePath, file);
|
|
2255
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
2256
|
+
const lines = content.split("\n");
|
|
2257
|
+
const matches = [];
|
|
2258
|
+
for (const line of lines) {
|
|
2259
|
+
if (line.toLowerCase().includes(queryLower)) {
|
|
2260
|
+
matches.push(line.trim());
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
if (matches.length > 0) {
|
|
2264
|
+
results.push({
|
|
2265
|
+
project: project.name,
|
|
2266
|
+
file,
|
|
2267
|
+
matches: matches.slice(0, 5)
|
|
2268
|
+
// Limit to 5 matches per file
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2608
2272
|
} catch {
|
|
2609
2273
|
}
|
|
2610
2274
|
}
|
|
2611
|
-
|
|
2612
|
-
config.mcpServers["rrce"] = {
|
|
2613
|
-
command: "npx",
|
|
2614
|
-
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
2615
|
-
};
|
|
2616
|
-
try {
|
|
2617
|
-
fs14.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
|
|
2618
|
-
return true;
|
|
2619
|
-
} catch {
|
|
2620
|
-
return false;
|
|
2621
|
-
}
|
|
2275
|
+
return results;
|
|
2622
2276
|
}
|
|
2623
|
-
function
|
|
2624
|
-
const
|
|
2625
|
-
|
|
2626
|
-
|
|
2277
|
+
async function indexKnowledge(projectName, force = false) {
|
|
2278
|
+
const config = loadMCPConfig();
|
|
2279
|
+
const projects = getExposedProjects();
|
|
2280
|
+
const project = projects.find((p) => p.name === projectName || p.path && p.path === projectName);
|
|
2281
|
+
if (!project) {
|
|
2282
|
+
return { success: false, message: `Project '${projectName}' not found`, filesIndexed: 0, filesSkipped: 0 };
|
|
2627
2283
|
}
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
}
|
|
2284
|
+
const projConfig = config.projects.find(
|
|
2285
|
+
(p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
|
|
2286
|
+
) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
|
|
2287
|
+
const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
|
|
2288
|
+
if (!isEnabled) {
|
|
2289
|
+
return { success: false, message: "Semantic Search is not enabled for this project", filesIndexed: 0, filesSkipped: 0 };
|
|
2634
2290
|
}
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2291
|
+
const scanRoot = project.sourcePath || project.path || project.dataPath;
|
|
2292
|
+
if (!fs14.existsSync(scanRoot)) {
|
|
2293
|
+
return { success: false, message: "Project root not found", filesIndexed: 0, filesSkipped: 0 };
|
|
2294
|
+
}
|
|
2295
|
+
const INDEXABLE_EXTENSIONS = [
|
|
2296
|
+
".ts",
|
|
2297
|
+
".tsx",
|
|
2298
|
+
".js",
|
|
2299
|
+
".jsx",
|
|
2300
|
+
".mjs",
|
|
2301
|
+
".cjs",
|
|
2302
|
+
".py",
|
|
2303
|
+
".pyw",
|
|
2304
|
+
".go",
|
|
2305
|
+
".rs",
|
|
2306
|
+
".java",
|
|
2307
|
+
".kt",
|
|
2308
|
+
".kts",
|
|
2309
|
+
".c",
|
|
2310
|
+
".cpp",
|
|
2311
|
+
".h",
|
|
2312
|
+
".hpp",
|
|
2313
|
+
".cs",
|
|
2314
|
+
".rb",
|
|
2315
|
+
".php",
|
|
2316
|
+
".swift",
|
|
2317
|
+
".md",
|
|
2318
|
+
".mdx",
|
|
2319
|
+
".json",
|
|
2320
|
+
".yaml",
|
|
2321
|
+
".yml",
|
|
2322
|
+
".toml",
|
|
2323
|
+
".sh",
|
|
2324
|
+
".bash",
|
|
2325
|
+
".zsh",
|
|
2326
|
+
".sql",
|
|
2327
|
+
".html",
|
|
2328
|
+
".css",
|
|
2329
|
+
".scss",
|
|
2330
|
+
".sass",
|
|
2331
|
+
".less"
|
|
2332
|
+
];
|
|
2333
|
+
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv", "target", "vendor"];
|
|
2640
2334
|
try {
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2335
|
+
const indexPath = path15.join(project.knowledgePath || path15.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
|
|
2336
|
+
const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
|
|
2337
|
+
const rag = new RAGService(indexPath, model);
|
|
2338
|
+
let indexed = 0;
|
|
2339
|
+
let skipped = 0;
|
|
2340
|
+
const scanDir = async (dir) => {
|
|
2341
|
+
const entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
2342
|
+
for (const entry of entries) {
|
|
2343
|
+
const fullPath = path15.join(dir, entry.name);
|
|
2344
|
+
if (entry.isDirectory()) {
|
|
2345
|
+
if (SKIP_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
|
|
2346
|
+
continue;
|
|
2347
|
+
}
|
|
2348
|
+
await scanDir(fullPath);
|
|
2349
|
+
} else if (entry.isFile()) {
|
|
2350
|
+
const ext = path15.extname(entry.name).toLowerCase();
|
|
2351
|
+
if (!INDEXABLE_EXTENSIONS.includes(ext)) {
|
|
2352
|
+
continue;
|
|
2353
|
+
}
|
|
2354
|
+
try {
|
|
2355
|
+
const stat = fs14.statSync(fullPath);
|
|
2356
|
+
const mtime = force ? void 0 : stat.mtimeMs;
|
|
2357
|
+
const content = fs14.readFileSync(fullPath, "utf-8");
|
|
2358
|
+
const wasIndexed = await rag.indexFile(fullPath, content, mtime);
|
|
2359
|
+
if (wasIndexed) {
|
|
2360
|
+
indexed++;
|
|
2361
|
+
} else {
|
|
2362
|
+
skipped++;
|
|
2363
|
+
}
|
|
2364
|
+
} catch (err) {
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
await scanDir(scanRoot);
|
|
2370
|
+
rag.markFullIndex();
|
|
2371
|
+
const stats = rag.getStats();
|
|
2372
|
+
return {
|
|
2373
|
+
success: true,
|
|
2374
|
+
message: `Indexed ${indexed} files, skipped ${skipped} unchanged. Total: ${stats.totalChunks} chunks from ${stats.totalFiles} files.`,
|
|
2375
|
+
filesIndexed: indexed,
|
|
2376
|
+
filesSkipped: skipped
|
|
2377
|
+
};
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
return { success: false, message: `Indexing failed: ${error}`, filesIndexed: 0, filesSkipped: 0 };
|
|
2645
2380
|
}
|
|
2646
2381
|
}
|
|
2647
|
-
function
|
|
2648
|
-
const
|
|
2649
|
-
const
|
|
2650
|
-
|
|
2651
|
-
|
|
2382
|
+
function getContextPreamble() {
|
|
2383
|
+
const projects = getExposedProjects();
|
|
2384
|
+
const activeProject = detectActiveProject();
|
|
2385
|
+
let contextPreamble = "";
|
|
2386
|
+
if (activeProject) {
|
|
2387
|
+
const rrceHome = process.env.RRCE_HOME || path15.join(__require("os").homedir(), ".rrce-workflow");
|
|
2388
|
+
const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
2389
|
+
const rrceData = activeProject.dataPath;
|
|
2390
|
+
contextPreamble += `
|
|
2391
|
+
## System Resolved Paths
|
|
2392
|
+
Use these values directly in your operations. Do NOT manually resolve paths.
|
|
2393
|
+
|
|
2394
|
+
| Variable | Value |
|
|
2395
|
+
|----------|-------|
|
|
2396
|
+
| \`WORKSPACE_ROOT\` | \`${workspaceRoot}\` |
|
|
2397
|
+
| \`WORKSPACE_NAME\` | \`${activeProject.name}\` |
|
|
2398
|
+
| \`RRCE_DATA\` | \`${rrceData}\` |
|
|
2399
|
+
| \`RRCE_HOME\` | \`${rrceHome}\` |
|
|
2400
|
+
|
|
2401
|
+
`;
|
|
2652
2402
|
}
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2403
|
+
const projectList = projects.map((p) => {
|
|
2404
|
+
const isActive = activeProject && p.dataPath === activeProject.dataPath;
|
|
2405
|
+
return `- ${p.name} (${p.source}) ${isActive ? "**[ACTIVE]**" : ""}`;
|
|
2406
|
+
}).join("\n");
|
|
2407
|
+
contextPreamble += `
|
|
2408
|
+
## Available Projects
|
|
2409
|
+
${projectList}
|
|
2410
|
+
`;
|
|
2411
|
+
if (projects.length === 0) {
|
|
2412
|
+
contextPreamble += `
|
|
2413
|
+
WARNING: No projects are currently exposed to the MCP server.
|
|
2414
|
+
Run 'npx rrce-workflow mcp configure' to select projects to expose.
|
|
2415
|
+
`;
|
|
2659
2416
|
}
|
|
2660
|
-
if (
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
try {
|
|
2666
|
-
fs14.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
2667
|
-
return true;
|
|
2668
|
-
} catch {
|
|
2669
|
-
return false;
|
|
2417
|
+
if (activeProject) {
|
|
2418
|
+
contextPreamble += `
|
|
2419
|
+
Current Active Workspace: ${activeProject.name}
|
|
2420
|
+
All file operations should be relative to WORKSPACE_ROOT shown above.
|
|
2421
|
+
`;
|
|
2670
2422
|
}
|
|
2423
|
+
contextPreamble += `
|
|
2424
|
+
---
|
|
2425
|
+
`;
|
|
2426
|
+
return contextPreamble;
|
|
2671
2427
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2428
|
+
var init_resources = __esm({
|
|
2429
|
+
"src/mcp/resources.ts"() {
|
|
2430
|
+
"use strict";
|
|
2431
|
+
init_config();
|
|
2432
|
+
init_detection();
|
|
2433
|
+
init_detection_service();
|
|
2434
|
+
init_rag();
|
|
2676
2435
|
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2436
|
+
});
|
|
2437
|
+
|
|
2438
|
+
// src/mcp/handlers/resources.ts
|
|
2439
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
2440
|
+
import {
|
|
2441
|
+
ListResourcesRequestSchema,
|
|
2442
|
+
ReadResourceRequestSchema
|
|
2443
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
2444
|
+
function registerResourceHandlers(server) {
|
|
2445
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
2446
|
+
logger.debug("Listing resources");
|
|
2447
|
+
const projects = getExposedProjects();
|
|
2448
|
+
const resources = [];
|
|
2449
|
+
resources.push({
|
|
2450
|
+
uri: "rrce://projects",
|
|
2451
|
+
name: "Project List",
|
|
2452
|
+
description: "List of all RRCE projects exposed via MCP",
|
|
2453
|
+
mimeType: "application/json"
|
|
2454
|
+
});
|
|
2455
|
+
for (const project of projects) {
|
|
2456
|
+
const config = loadMCPConfig();
|
|
2457
|
+
const permissions = getProjectPermissions(config, project.name, project.dataPath);
|
|
2458
|
+
if (permissions.knowledge) {
|
|
2459
|
+
resources.push({
|
|
2460
|
+
uri: `rrce://projects/${project.name}/context`,
|
|
2461
|
+
name: `${project.name} - Project Context`,
|
|
2462
|
+
description: `Project context and architecture for ${project.name}`,
|
|
2463
|
+
mimeType: "text/markdown"
|
|
2464
|
+
});
|
|
2465
|
+
}
|
|
2466
|
+
if (permissions.tasks) {
|
|
2467
|
+
resources.push({
|
|
2468
|
+
uri: `rrce://projects/${project.name}/tasks`,
|
|
2469
|
+
name: `${project.name} - Tasks`,
|
|
2470
|
+
description: `Task list and status for ${project.name}`,
|
|
2471
|
+
mimeType: "application/json"
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
return { resources };
|
|
2476
|
+
});
|
|
2477
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2478
|
+
const { uri } = request.params;
|
|
2479
|
+
logger.info(`Reading resource: ${uri}`);
|
|
2681
2480
|
try {
|
|
2682
|
-
|
|
2481
|
+
if (uri === "rrce://projects") {
|
|
2482
|
+
const projects = getExposedProjects();
|
|
2483
|
+
return {
|
|
2484
|
+
contents: [{
|
|
2485
|
+
uri,
|
|
2486
|
+
mimeType: "application/json",
|
|
2487
|
+
text: JSON.stringify(projects.map((p) => ({ name: p.name, source: p.source, path: p.path })), null, 2)
|
|
2488
|
+
}]
|
|
2489
|
+
};
|
|
2490
|
+
}
|
|
2491
|
+
const projectMatch = uri.match(/^rrce:\/\/projects\/([^/]+)\/(.+)$/);
|
|
2492
|
+
if (projectMatch && projectMatch[1] && projectMatch[2]) {
|
|
2493
|
+
const projectName = projectMatch[1];
|
|
2494
|
+
const resourceType = projectMatch[2];
|
|
2495
|
+
const content = resourceType === "context" ? getProjectContext(projectName) : JSON.stringify(getProjectTasks(projectName), null, 2);
|
|
2496
|
+
if (content === null) throw new Error(`Resource not found: ${uri}`);
|
|
2497
|
+
return {
|
|
2498
|
+
contents: [{
|
|
2499
|
+
uri,
|
|
2500
|
+
mimeType: resourceType === "tasks" ? "application/json" : "text/markdown",
|
|
2501
|
+
text: content
|
|
2502
|
+
}]
|
|
2503
|
+
};
|
|
2504
|
+
}
|
|
2505
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
2683
2506
|
} catch (error) {
|
|
2684
|
-
|
|
2507
|
+
logger.error(`Failed to read resource: ${uri}`, error);
|
|
2508
|
+
throw error;
|
|
2685
2509
|
}
|
|
2686
|
-
}
|
|
2687
|
-
if (!config.mcp) config.mcp = {};
|
|
2688
|
-
config.mcp["rrce"] = {
|
|
2689
|
-
type: "local",
|
|
2690
|
-
command: ["npx", "-y", "rrce-workflow", "mcp", "start"],
|
|
2691
|
-
enabled: true
|
|
2692
|
-
};
|
|
2693
|
-
try {
|
|
2694
|
-
fs14.writeFileSync(OPENCODE_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
2695
|
-
return true;
|
|
2696
|
-
} catch (error) {
|
|
2697
|
-
console.error("Failed to write OpenCode config:", error instanceof Error ? error.message : String(error));
|
|
2698
|
-
return false;
|
|
2699
|
-
}
|
|
2510
|
+
});
|
|
2700
2511
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2512
|
+
var init_resources2 = __esm({
|
|
2513
|
+
"src/mcp/handlers/resources.ts"() {
|
|
2514
|
+
"use strict";
|
|
2515
|
+
init_logger();
|
|
2516
|
+
init_config();
|
|
2517
|
+
init_resources();
|
|
2705
2518
|
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2519
|
+
});
|
|
2520
|
+
|
|
2521
|
+
// src/mcp/prompts.ts
|
|
2522
|
+
function getAllPrompts() {
|
|
2523
|
+
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
2524
|
+
return prompts.map((p) => {
|
|
2525
|
+
const args = [];
|
|
2526
|
+
if (p.frontmatter["required-args"]) {
|
|
2527
|
+
args.push(...p.frontmatter["required-args"].map((a) => ({
|
|
2528
|
+
name: a.name,
|
|
2529
|
+
description: a.prompt || a.name,
|
|
2530
|
+
required: true
|
|
2531
|
+
})));
|
|
2711
2532
|
}
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2533
|
+
if (p.frontmatter["optional-args"]) {
|
|
2534
|
+
args.push(...p.frontmatter["optional-args"].map((a) => ({
|
|
2535
|
+
name: a.name,
|
|
2536
|
+
description: a.prompt || a.name,
|
|
2537
|
+
required: false
|
|
2538
|
+
})));
|
|
2539
|
+
}
|
|
2540
|
+
const filename = p.filePath.split("/").pop() || "";
|
|
2541
|
+
const id = filename.replace(/\.md$/, "");
|
|
2542
|
+
return {
|
|
2543
|
+
id,
|
|
2544
|
+
name: p.frontmatter.name,
|
|
2545
|
+
description: p.frontmatter.description,
|
|
2546
|
+
arguments: args,
|
|
2547
|
+
content: p.content
|
|
2548
|
+
};
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2551
|
+
function getPromptDef(name) {
|
|
2552
|
+
const all = getAllPrompts();
|
|
2553
|
+
const search = name.toLowerCase();
|
|
2554
|
+
return all.find(
|
|
2555
|
+
(p) => p.name === name || p.id === name || p.name.toLowerCase() === search || p.id.toLowerCase() === search
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
function renderPrompt(content, args) {
|
|
2559
|
+
let rendered = content;
|
|
2560
|
+
for (const [key, val] of Object.entries(args)) {
|
|
2561
|
+
rendered = rendered.replace(new RegExp(`{{${key}}}`, "g"), val);
|
|
2718
2562
|
}
|
|
2563
|
+
return rendered;
|
|
2719
2564
|
}
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2565
|
+
var init_prompts2 = __esm({
|
|
2566
|
+
"src/mcp/prompts.ts"() {
|
|
2567
|
+
"use strict";
|
|
2568
|
+
init_prompts();
|
|
2724
2569
|
}
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2570
|
+
});
|
|
2571
|
+
|
|
2572
|
+
// src/mcp/handlers/tools.ts
|
|
2573
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
2574
|
+
import {
|
|
2575
|
+
ListToolsRequestSchema,
|
|
2576
|
+
CallToolRequestSchema
|
|
2577
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
2578
|
+
function registerToolHandlers(server) {
|
|
2579
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2580
|
+
const tools = [
|
|
2581
|
+
{
|
|
2582
|
+
name: "search_knowledge",
|
|
2583
|
+
description: "Search across all exposed project knowledge bases",
|
|
2584
|
+
inputSchema: {
|
|
2585
|
+
type: "object",
|
|
2586
|
+
properties: {
|
|
2587
|
+
query: { type: "string", description: "Search query to find in knowledge files" },
|
|
2588
|
+
project: { type: "string", description: "Optional: limit search to specific project name" }
|
|
2589
|
+
},
|
|
2590
|
+
required: ["query"]
|
|
2591
|
+
}
|
|
2592
|
+
},
|
|
2593
|
+
{
|
|
2594
|
+
name: "index_knowledge",
|
|
2595
|
+
description: "Update the semantic search index for a specific project",
|
|
2596
|
+
inputSchema: {
|
|
2597
|
+
type: "object",
|
|
2598
|
+
properties: {
|
|
2599
|
+
project: { type: "string", description: "Name of the project to index" },
|
|
2600
|
+
force: { type: "boolean", description: "Force re-indexing of all files" }
|
|
2601
|
+
},
|
|
2602
|
+
required: ["project"]
|
|
2603
|
+
}
|
|
2604
|
+
},
|
|
2605
|
+
{
|
|
2606
|
+
name: "list_projects",
|
|
2607
|
+
description: "List all projects exposed via MCP. Use these names for project-specific tools.",
|
|
2608
|
+
inputSchema: { type: "object", properties: {} }
|
|
2609
|
+
},
|
|
2610
|
+
{
|
|
2611
|
+
name: "get_project_context",
|
|
2612
|
+
description: "Get the project context/architecture for a specific project",
|
|
2613
|
+
inputSchema: {
|
|
2614
|
+
type: "object",
|
|
2615
|
+
properties: { project: { type: "string", description: "Name of the project to get context for" } },
|
|
2616
|
+
required: ["project"]
|
|
2617
|
+
}
|
|
2618
|
+
},
|
|
2619
|
+
{
|
|
2620
|
+
name: "list_agents",
|
|
2621
|
+
description: "List available agents (e.g. init, plan) and their arguments. Use this to discover which agent to call.",
|
|
2622
|
+
inputSchema: { type: "object", properties: {} }
|
|
2623
|
+
},
|
|
2624
|
+
{
|
|
2625
|
+
name: "get_agent_prompt",
|
|
2626
|
+
description: 'Get the system prompt for a specific agent. Accepts agent Name (e.g. "RRCE Init") or ID (e.g. "init").',
|
|
2627
|
+
inputSchema: {
|
|
2628
|
+
type: "object",
|
|
2629
|
+
properties: {
|
|
2630
|
+
agent: { type: "string", description: "Name of the agent (e.g. init, plan, execute)" },
|
|
2631
|
+
args: { type: "object", description: "Arguments for the agent prompt", additionalProperties: true }
|
|
2632
|
+
},
|
|
2633
|
+
required: ["agent"]
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
];
|
|
2637
|
+
const projects = getExposedProjects();
|
|
2638
|
+
if (projects.length === 0) {
|
|
2639
|
+
tools.push({
|
|
2640
|
+
name: "help_setup",
|
|
2641
|
+
description: "Get help on how to configure projects for the RRCE MCP Server",
|
|
2642
|
+
inputSchema: { type: "object", properties: {} }
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
return { tools };
|
|
2646
|
+
});
|
|
2647
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2648
|
+
const { name, arguments: args } = request.params;
|
|
2649
|
+
logger.info(`Calling tool: ${name}`, args);
|
|
2650
|
+
try {
|
|
2651
|
+
switch (name) {
|
|
2652
|
+
case "search_knowledge": {
|
|
2653
|
+
const params = args;
|
|
2654
|
+
const results = await searchKnowledge(params.query, params.project);
|
|
2655
|
+
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
2656
|
+
}
|
|
2657
|
+
case "index_knowledge": {
|
|
2658
|
+
const params = args;
|
|
2659
|
+
const result = await indexKnowledge(params.project, params.force);
|
|
2660
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
2661
|
+
}
|
|
2662
|
+
case "list_projects": {
|
|
2663
|
+
const projects = getExposedProjects();
|
|
2664
|
+
const list = projects.map((p) => ({ name: p.name, source: p.source, path: p.path }));
|
|
2665
|
+
return {
|
|
2666
|
+
content: [{
|
|
2667
|
+
type: "text",
|
|
2668
|
+
text: JSON.stringify(list, null, 2) + "\n\nTip: Use these project names for tools like `get_project_context` or `index_knowledge`."
|
|
2669
|
+
}]
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
case "get_project_context": {
|
|
2673
|
+
const context = getProjectContext(args.project);
|
|
2674
|
+
if (!context) {
|
|
2675
|
+
const projects = getExposedProjects().map((p) => p.name).join(", ");
|
|
2676
|
+
const msg = `No project context found for "${args.project}".
|
|
2677
|
+
Available projects: ${projects}`;
|
|
2678
|
+
logger.warn(msg);
|
|
2679
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
2680
|
+
}
|
|
2681
|
+
return { content: [{ type: "text", text: context }] };
|
|
2682
|
+
}
|
|
2683
|
+
case "list_agents": {
|
|
2684
|
+
const prompts = getAllPrompts();
|
|
2685
|
+
return {
|
|
2686
|
+
content: [{
|
|
2687
|
+
type: "text",
|
|
2688
|
+
text: JSON.stringify(prompts.map((p) => ({
|
|
2689
|
+
name: p.name,
|
|
2690
|
+
id: p.id,
|
|
2691
|
+
description: p.description,
|
|
2692
|
+
arguments: p.arguments
|
|
2693
|
+
})), null, 2) + "\n\nTip: Retrieve the prompt for an agent using `get_agent_prompt` with its name or ID."
|
|
2694
|
+
}]
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
case "get_agent_prompt": {
|
|
2698
|
+
const params = args;
|
|
2699
|
+
const agentName = params.agent;
|
|
2700
|
+
const promptDef = getPromptDef(agentName);
|
|
2701
|
+
if (!promptDef) {
|
|
2702
|
+
const available = getAllPrompts().map((p) => `${p.name} (id: ${p.id})`).join(", ");
|
|
2703
|
+
throw new Error(`Agent not found: ${agentName}. Available agents: ${available}`);
|
|
2704
|
+
}
|
|
2705
|
+
const renderArgs = params.args || {};
|
|
2706
|
+
const stringArgs = {};
|
|
2707
|
+
for (const [key, val] of Object.entries(renderArgs)) {
|
|
2708
|
+
stringArgs[key] = String(val);
|
|
2709
|
+
}
|
|
2710
|
+
const content = renderPrompt(promptDef.content, stringArgs);
|
|
2711
|
+
const contextPreamble = getContextPreamble();
|
|
2712
|
+
return { content: [{ type: "text", text: contextPreamble + content }] };
|
|
2713
|
+
}
|
|
2714
|
+
case "help_setup": {
|
|
2715
|
+
const msg = `
|
|
2716
|
+
RRCE MCP Server is running, but no projects are configured/exposed.
|
|
2717
|
+
|
|
2718
|
+
To fix this:
|
|
2719
|
+
1. Open a terminal.
|
|
2720
|
+
2. Run: npx rrce-workflow mcp configure
|
|
2721
|
+
3. Select the projects you want to expose to the AI.
|
|
2722
|
+
4. Restart the MCP server (or it may pick up changes automatically).
|
|
2723
|
+
`;
|
|
2724
|
+
return { content: [{ type: "text", text: msg }] };
|
|
2725
|
+
}
|
|
2726
|
+
default:
|
|
2727
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
2728
|
+
}
|
|
2729
|
+
} catch (error) {
|
|
2730
|
+
logger.error(`Tool execution failed: ${name}`, error);
|
|
2731
|
+
throw error;
|
|
2730
2732
|
}
|
|
2731
|
-
|
|
2732
|
-
fs14.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2) + "\n");
|
|
2733
|
-
return true;
|
|
2734
|
-
} catch (error) {
|
|
2735
|
-
console.error("Failed to uninstall from Antigravity:", error instanceof Error ? error.message : String(error));
|
|
2736
|
-
return false;
|
|
2737
|
-
}
|
|
2733
|
+
});
|
|
2738
2734
|
}
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2735
|
+
var init_tools = __esm({
|
|
2736
|
+
"src/mcp/handlers/tools.ts"() {
|
|
2737
|
+
"use strict";
|
|
2738
|
+
init_logger();
|
|
2739
|
+
init_resources();
|
|
2740
|
+
init_prompts2();
|
|
2743
2741
|
}
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2742
|
+
});
|
|
2743
|
+
|
|
2744
|
+
// src/mcp/handlers/prompts.ts
|
|
2745
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
2746
|
+
import {
|
|
2747
|
+
ListPromptsRequestSchema,
|
|
2748
|
+
GetPromptRequestSchema
|
|
2749
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
2750
|
+
import * as path16 from "path";
|
|
2751
|
+
function registerPromptHandlers(server) {
|
|
2752
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
2753
|
+
logger.debug("Listing prompts");
|
|
2754
|
+
const prompts = getAllPrompts();
|
|
2755
|
+
return {
|
|
2756
|
+
prompts: prompts.map((p) => ({
|
|
2757
|
+
name: p.name,
|
|
2758
|
+
description: p.description,
|
|
2759
|
+
arguments: p.arguments.map((a) => ({
|
|
2760
|
+
name: a.name,
|
|
2761
|
+
description: a.description,
|
|
2762
|
+
required: a.required
|
|
2763
|
+
}))
|
|
2764
|
+
}))
|
|
2765
|
+
};
|
|
2766
|
+
});
|
|
2767
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
2768
|
+
const { name, arguments: args } = request.params;
|
|
2769
|
+
logger.info(`Getting prompt: ${name}`, args);
|
|
2770
|
+
const promptDef = getPromptDef(name);
|
|
2771
|
+
if (!promptDef) {
|
|
2772
|
+
logger.error(`Prompt not found: ${name}`);
|
|
2773
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
2749
2774
|
}
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2775
|
+
try {
|
|
2776
|
+
const providedArgs = args || {};
|
|
2777
|
+
const missingArgs = promptDef.arguments.filter((a) => a.required && !providedArgs[a.name]).map((a) => a.name);
|
|
2778
|
+
if (missingArgs.length > 0) {
|
|
2779
|
+
throw new Error(`Missing required arguments: ${missingArgs.join(", ")}`);
|
|
2780
|
+
}
|
|
2781
|
+
const renderArgs = {};
|
|
2782
|
+
for (const [key, val] of Object.entries(providedArgs)) {
|
|
2783
|
+
renderArgs[key] = String(val);
|
|
2784
|
+
}
|
|
2785
|
+
const activeProject = detectActiveProject();
|
|
2786
|
+
const DEFAULT_RRCE_HOME = getEffectiveGlobalPath();
|
|
2787
|
+
let resolvedRrceData = ".rrce-workflow/";
|
|
2788
|
+
let resolvedRrceHome = DEFAULT_RRCE_HOME;
|
|
2789
|
+
let resolvedWorkspaceRoot = process.cwd();
|
|
2790
|
+
let resolvedWorkspaceName = "current-project";
|
|
2791
|
+
if (activeProject) {
|
|
2792
|
+
resolvedRrceData = activeProject.dataPath + "/";
|
|
2793
|
+
resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
2794
|
+
resolvedWorkspaceName = activeProject.name;
|
|
2795
|
+
if (activeProject.source === "global") {
|
|
2796
|
+
const workspacesDir = path16.dirname(activeProject.dataPath);
|
|
2797
|
+
resolvedRrceHome = path16.dirname(workspacesDir);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
if (!renderArgs["RRCE_DATA"]) renderArgs["RRCE_DATA"] = resolvedRrceData;
|
|
2801
|
+
if (!renderArgs["RRCE_HOME"]) renderArgs["RRCE_HOME"] = resolvedRrceHome;
|
|
2802
|
+
if (!renderArgs["WORKSPACE_ROOT"]) renderArgs["WORKSPACE_ROOT"] = resolvedWorkspaceRoot;
|
|
2803
|
+
if (!renderArgs["WORKSPACE_NAME"]) renderArgs["WORKSPACE_NAME"] = resolvedWorkspaceName;
|
|
2804
|
+
const content = renderPrompt(promptDef.content, renderArgs);
|
|
2805
|
+
let contextPreamble = getContextPreamble();
|
|
2806
|
+
contextPreamble += `
|
|
2807
|
+
### System Resolved Paths (OVERRIDE)
|
|
2808
|
+
The system has pre-resolved the configuration for this project. Use these values instead of manual resolution:
|
|
2809
|
+
- **RRCE_DATA**: \`${resolvedRrceData}\` (Stores knowledge, tasks, refs)
|
|
2810
|
+
- **WORKSPACE_ROOT**: \`${resolvedWorkspaceRoot}\` (Source code location)
|
|
2811
|
+
- **RRCE_HOME**: \`${resolvedRrceHome}\`
|
|
2812
|
+
- **Current Project**: ${resolvedWorkspaceName}
|
|
2813
|
+
`;
|
|
2814
|
+
return {
|
|
2815
|
+
messages: [
|
|
2816
|
+
{
|
|
2817
|
+
role: "user",
|
|
2818
|
+
content: {
|
|
2819
|
+
type: "text",
|
|
2820
|
+
text: contextPreamble + content
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
]
|
|
2824
|
+
};
|
|
2825
|
+
} catch (error) {
|
|
2826
|
+
logger.error(`Failed to get prompt: ${name}`, error);
|
|
2827
|
+
throw error;
|
|
2768
2828
|
}
|
|
2769
|
-
|
|
2770
|
-
fs14.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2) + "\n");
|
|
2771
|
-
return true;
|
|
2772
|
-
} catch (error) {
|
|
2773
|
-
console.error("Failed to uninstall from VSCode (Global):", error instanceof Error ? error.message : String(error));
|
|
2774
|
-
return false;
|
|
2775
|
-
}
|
|
2829
|
+
});
|
|
2776
2830
|
}
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2831
|
+
var init_prompts3 = __esm({
|
|
2832
|
+
"src/mcp/handlers/prompts.ts"() {
|
|
2833
|
+
"use strict";
|
|
2834
|
+
init_logger();
|
|
2835
|
+
init_resources();
|
|
2836
|
+
init_prompts2();
|
|
2837
|
+
init_paths();
|
|
2782
2838
|
}
|
|
2839
|
+
});
|
|
2840
|
+
|
|
2841
|
+
// src/mcp/server.ts
|
|
2842
|
+
var server_exports = {};
|
|
2843
|
+
__export(server_exports, {
|
|
2844
|
+
getMCPServerStatus: () => getMCPServerStatus,
|
|
2845
|
+
startMCPServer: () => startMCPServer,
|
|
2846
|
+
stopMCPServer: () => stopMCPServer
|
|
2847
|
+
});
|
|
2848
|
+
import { Server as Server4 } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2849
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2850
|
+
async function startMCPServer(options = {}) {
|
|
2783
2851
|
try {
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2852
|
+
logger.info("Starting MCP Server...");
|
|
2853
|
+
process.on("uncaughtException", (error) => {
|
|
2854
|
+
logger.error("Uncaught Exception", error);
|
|
2855
|
+
console.error("Uncaught Exception:", error);
|
|
2856
|
+
});
|
|
2857
|
+
process.on("unhandledRejection", (reason) => {
|
|
2858
|
+
logger.error("Unhandled Rejection", reason);
|
|
2859
|
+
console.error("Unhandled Rejection:", reason);
|
|
2860
|
+
});
|
|
2861
|
+
const config = loadMCPConfig();
|
|
2862
|
+
mcpServer = new Server4(
|
|
2863
|
+
{ name: "rrce-mcp-hub", version: "1.0.0" },
|
|
2864
|
+
{ capabilities: { resources: {}, tools: {}, prompts: {} } }
|
|
2865
|
+
);
|
|
2866
|
+
mcpServer.onerror = (error) => {
|
|
2867
|
+
logger.error("MCP Server Error", error);
|
|
2868
|
+
};
|
|
2869
|
+
registerResourceHandlers(mcpServer);
|
|
2870
|
+
registerToolHandlers(mcpServer);
|
|
2871
|
+
registerPromptHandlers(mcpServer);
|
|
2872
|
+
if (!options.interactive) {
|
|
2873
|
+
const transport = new StdioServerTransport();
|
|
2874
|
+
await mcpServer.connect(transport);
|
|
2875
|
+
} else {
|
|
2876
|
+
logger.info("Running in interactive mode (Stdio transport detached)");
|
|
2788
2877
|
}
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2878
|
+
serverState = { running: true, port: config.server.port, pid: process.pid };
|
|
2879
|
+
const exposed = getExposedProjects().map((p) => p.name).join(", ");
|
|
2880
|
+
logger.info(`RRCE MCP Hub started (pid: ${process.pid})`, { exposedProjects: exposed });
|
|
2881
|
+
if (!options.interactive) {
|
|
2882
|
+
console.error(`RRCE MCP Hub started (pid: ${process.pid})`);
|
|
2883
|
+
console.error(`Exposed projects: ${exposed}`);
|
|
2884
|
+
}
|
|
2885
|
+
return { port: config.server.port, pid: process.pid };
|
|
2792
2886
|
} catch (error) {
|
|
2793
|
-
|
|
2794
|
-
|
|
2887
|
+
logger.error("Failed to start MCP server", error);
|
|
2888
|
+
throw error;
|
|
2795
2889
|
}
|
|
2796
2890
|
}
|
|
2797
|
-
function
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
return uninstallFromClaude();
|
|
2803
|
-
case "vscode-global":
|
|
2804
|
-
return uninstallFromVSCodeGlobal();
|
|
2805
|
-
case "vscode-workspace":
|
|
2806
|
-
return workspacePath ? uninstallFromVSCodeWorkspace(workspacePath) : false;
|
|
2807
|
-
case "opencode":
|
|
2808
|
-
return uninstallFromOpenCode();
|
|
2809
|
-
default:
|
|
2810
|
-
return false;
|
|
2891
|
+
function stopMCPServer() {
|
|
2892
|
+
if (mcpServer) {
|
|
2893
|
+
logger.info("Stopping MCP Server...");
|
|
2894
|
+
mcpServer.close();
|
|
2895
|
+
mcpServer = null;
|
|
2811
2896
|
}
|
|
2897
|
+
serverState = { running: false };
|
|
2898
|
+
logger.info("RRCE MCP Hub stopped");
|
|
2812
2899
|
}
|
|
2813
|
-
function
|
|
2814
|
-
|
|
2815
|
-
case "antigravity":
|
|
2816
|
-
return "Antigravity IDE";
|
|
2817
|
-
case "claude":
|
|
2818
|
-
return "Claude Desktop";
|
|
2819
|
-
case "vscode-global":
|
|
2820
|
-
return "VSCode (Global)";
|
|
2821
|
-
case "vscode-workspace":
|
|
2822
|
-
return "VSCode (Workspace)";
|
|
2823
|
-
case "opencode":
|
|
2824
|
-
return "OpenCode";
|
|
2825
|
-
default:
|
|
2826
|
-
return target;
|
|
2827
|
-
}
|
|
2900
|
+
function getMCPServerStatus() {
|
|
2901
|
+
return { ...serverState };
|
|
2828
2902
|
}
|
|
2829
|
-
var
|
|
2830
|
-
var
|
|
2831
|
-
"src/mcp/
|
|
2903
|
+
var serverState, mcpServer;
|
|
2904
|
+
var init_server = __esm({
|
|
2905
|
+
"src/mcp/server.ts"() {
|
|
2832
2906
|
"use strict";
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2907
|
+
init_logger();
|
|
2908
|
+
init_config();
|
|
2909
|
+
init_resources();
|
|
2910
|
+
init_resources2();
|
|
2911
|
+
init_tools();
|
|
2912
|
+
init_prompts3();
|
|
2913
|
+
serverState = { running: false };
|
|
2914
|
+
mcpServer = null;
|
|
2837
2915
|
}
|
|
2838
2916
|
});
|
|
2839
2917
|
|
|
@@ -4131,13 +4209,18 @@ async function runExpressSetup(workspacePath, workspaceName, existingProjects, s
|
|
|
4131
4209
|
process.exit(0);
|
|
4132
4210
|
}
|
|
4133
4211
|
}
|
|
4212
|
+
const toolsPreview = [];
|
|
4213
|
+
if (isOpenCodeInstalled()) toolsPreview.push("OpenCode");
|
|
4214
|
+
if (isVSCodeInstalled()) toolsPreview.push("GitHub Copilot");
|
|
4215
|
+
if (isAntigravityInstalled()) toolsPreview.push("Antigravity");
|
|
4216
|
+
const toolsText = toolsPreview.length > 0 ? toolsPreview.join(", ") : "None detected";
|
|
4134
4217
|
note9(
|
|
4135
4218
|
`${pc11.bold("Express Setup will configure:")}
|
|
4136
4219
|
\u2022 Storage: ${storageMode === "global" ? "Global" : "Workspace"}
|
|
4137
4220
|
\u2022 MCP Server: Enabled
|
|
4138
4221
|
\u2022 Semantic Search (RAG): Enabled
|
|
4139
4222
|
\u2022 Git ignore entries: Added (as comments)
|
|
4140
|
-
\u2022 AI Tools:
|
|
4223
|
+
\u2022 AI Tools: ${toolsText}`,
|
|
4141
4224
|
"Configuration Preview"
|
|
4142
4225
|
);
|
|
4143
4226
|
const confirmed = await confirm6({
|
|
@@ -4148,10 +4231,14 @@ async function runExpressSetup(workspacePath, workspaceName, existingProjects, s
|
|
|
4148
4231
|
cancel3("Setup cancelled.");
|
|
4149
4232
|
process.exit(0);
|
|
4150
4233
|
}
|
|
4234
|
+
const defaultTools = [];
|
|
4235
|
+
if (isOpenCodeInstalled()) defaultTools.push("opencode");
|
|
4236
|
+
if (isVSCodeInstalled()) defaultTools.push("copilot");
|
|
4237
|
+
if (isAntigravityInstalled()) defaultTools.push("antigravity");
|
|
4151
4238
|
const config = {
|
|
4152
4239
|
storageMode,
|
|
4153
4240
|
globalPath: customGlobalPath,
|
|
4154
|
-
tools:
|
|
4241
|
+
tools: defaultTools,
|
|
4155
4242
|
linkedProjects: [],
|
|
4156
4243
|
addToGitignore: false,
|
|
4157
4244
|
exposeToMCP: true,
|
|
@@ -4239,6 +4326,7 @@ async function executeSetup(config, workspacePath, workspaceName, allProjects, s
|
|
|
4239
4326
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, config.globalPath);
|
|
4240
4327
|
}
|
|
4241
4328
|
await registerWithMCP(config, workspacePath, workspaceName);
|
|
4329
|
+
const ideResults = installToSelectedIDEs(config.tools);
|
|
4242
4330
|
s.stop("Configuration generated");
|
|
4243
4331
|
const dataSummary = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
|
|
4244
4332
|
const summary = [
|
|
@@ -4246,8 +4334,14 @@ async function executeSetup(config, workspacePath, workspaceName, allProjects, s
|
|
|
4246
4334
|
config.tools.length > 0 ? `${pc11.green("\u2713")} Tools: ${config.tools.join(", ")}` : null,
|
|
4247
4335
|
config.exposeToMCP ? `${pc11.green("\u2713")} MCP server configured` : null,
|
|
4248
4336
|
config.enableRAG ? `${pc11.green("\u2713")} Semantic Search enabled` : null,
|
|
4249
|
-
config.linkedProjects.length > 0 ? `${pc11.green("\u2713")} Linked ${config.linkedProjects.length} project(s)` : null
|
|
4337
|
+
config.linkedProjects.length > 0 ? `${pc11.green("\u2713")} Linked ${config.linkedProjects.length} project(s)` : null,
|
|
4338
|
+
ideResults.success.length > 0 ? `${pc11.green("\u2713")} RRCE installed to: ${ideResults.success.join(", ")}` : null,
|
|
4339
|
+
ideResults.failed.length > 0 ? `${pc11.yellow("\u26A0")} Failed to install to: ${ideResults.failed.join(", ")}` : null
|
|
4250
4340
|
].filter(Boolean);
|
|
4341
|
+
if (ideResults.success.length > 0) {
|
|
4342
|
+
summary.push("");
|
|
4343
|
+
summary.push(pc11.dim("\u{1F4A1} You may need to restart your IDE or refresh MCP config for changes to take effect."));
|
|
4344
|
+
}
|
|
4251
4345
|
note9(summary.join("\n"), "Setup Complete");
|
|
4252
4346
|
} catch (error) {
|
|
4253
4347
|
s.stop("Error occurred");
|
|
@@ -4288,6 +4382,7 @@ var init_setup_flow = __esm({
|
|
|
4288
4382
|
"use strict";
|
|
4289
4383
|
init_detection();
|
|
4290
4384
|
init_tui_utils();
|
|
4385
|
+
init_install();
|
|
4291
4386
|
init_setup_prompts();
|
|
4292
4387
|
init_setup_actions();
|
|
4293
4388
|
init_gitignore();
|