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/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/commands/wizard/setup-prompts.ts
676
- import { select as select2, multiselect, confirm, isCancel as isCancel2, cancel } from "@clack/prompts";
677
- import pc3 from "picocolors";
678
- async function promptStorageMode() {
679
- const result = await select2({
680
- message: "Where should workflow data be stored?",
681
- options: [
682
- { value: "global", label: "Global (~/.rrce-workflow/)", hint: "Cross-project access, clean workspace" },
683
- { value: "workspace", label: "Workspace (.rrce-workflow/)", hint: "Self-contained, version with repo" }
684
- ],
685
- initialValue: "global"
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
- async function promptTools() {
694
- const result = await multiselect({
695
- message: "Which AI tools do you use?",
696
- options: [
697
- { value: "copilot", label: "GitHub Copilot", hint: "VSCode" },
698
- { value: "antigravity", label: "Antigravity IDE" }
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
- async function promptMCPExposure() {
709
- const result = await confirm({
710
- message: "Expose this project to MCP (AI Agent) server?",
711
- initialValue: true
712
- });
713
- if (isCancel2(result)) {
714
- cancel("Setup cancelled.");
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
- async function promptLinkedProjects(existingProjects) {
720
- if (existingProjects.length === 0) {
721
- return [];
722
- }
723
- const result = await multiselect({
724
- message: "Link knowledge from other projects?",
725
- options: existingProjects.map((project) => ({
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
- async function promptGitignore() {
741
- const result = await confirm({
742
- message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
743
- initialValue: false
744
- });
745
- if (isCancel2(result)) {
746
- cancel("Setup cancelled.");
747
- process.exit(0);
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
- async function promptRAG() {
752
- const result = await confirm({
753
- message: `Enable Semantic Search (Local Mini RAG)?
754
- ${pc3.yellow("\u26A0 First use will download a ~100MB model")}`,
755
- initialValue: true
756
- });
757
- if (isCancel2(result)) {
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
- async function promptConfirmation() {
764
- const result = await confirm({
765
- message: "Create configuration?",
766
- initialValue: true
767
- });
768
- if (isCancel2(result)) {
769
- cancel("Setup cancelled.");
770
- process.exit(0);
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
- var init_setup_prompts = __esm({
775
- "src/commands/wizard/setup-prompts.ts"() {
776
- "use strict";
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
- // src/types/prompt.ts
781
- import { z } from "zod";
782
- var PromptArgSchema, AutoIdentitySchema, PromptFrontmatterSchema;
783
- var init_prompt = __esm({
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
- // src/lib/prompts.ts
808
- import * as fs5 from "fs";
809
- import * as path6 from "path";
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
- const fileContent = fs5.readFileSync(filePath, "utf-8");
815
- const { data, content } = matter(fileContent);
816
- const parsed = PromptFrontmatterSchema.safeParse(data);
817
- if (!parsed.success) {
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 loadPromptsFromDir(dirPath) {
832
- if (!fs5.existsSync(dirPath)) {
833
- return [];
784
+ function installToClaude() {
785
+ const dir = path6.dirname(CLAUDE_CONFIG);
786
+ if (!fs5.existsSync(dir)) {
787
+ fs5.mkdirSync(dir, { recursive: true });
834
788
  }
835
- const files = fs5.readdirSync(dirPath).filter((f) => f.endsWith(".md"));
836
- const prompts = [];
837
- for (const file of files) {
838
- const prompt = parsePromptFile(path6.join(dirPath, file));
839
- if (prompt) {
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
- return prompts;
844
- }
845
- function getAgentCoreDir() {
846
- if (__dirname.includes("/src/") || __dirname.includes("\\src\\")) {
847
- if (fs5.existsSync(path6.join(process.cwd(), "agent-core"))) {
848
- return path6.join(process.cwd(), "agent-core");
849
- }
850
- return path6.resolve(__dirname, "../..", "agent-core");
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 getAgentCorePromptsDir() {
855
- return path6.join(getAgentCoreDir(), "prompts");
856
- }
857
- var __filename, __dirname;
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
- function copyDirRecursive(src, dest) {
880
- const entries = fs6.readdirSync(src, { withFileTypes: true });
881
- for (const entry of entries) {
882
- const srcPath = path7.join(src, entry.name);
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
- var init_utils = __esm({
893
- "src/commands/wizard/utils.ts"() {
894
- "use strict";
895
- init_paths();
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
- const content = fs7.readFileSync(workspaceFilePath, "utf-8");
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 (!workspace.settings) {
916
- workspace.settings = {};
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
- workspace.folders = workspace.folders.filter(
919
- (f) => f.path === "." || !f.name?.startsWith("\u{1F4C1}") && !f.name?.startsWith("\u{1F4DA}") && !f.name?.startsWith("\u{1F4CE}") && !f.name?.startsWith("\u{1F4CB}")
920
- );
921
- const mainFolderIndex = workspace.folders.findIndex((f) => f.path === ".");
922
- if (mainFolderIndex === -1) {
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
- const referenceFolderPaths = [];
934
- const isDetectedProjects = linkedProjects.length > 0 && typeof linkedProjects[0] === "object";
935
- if (isDetectedProjects) {
936
- const projects = linkedProjects;
937
- for (const project of projects) {
938
- const sourceLabel = project.source === "global" ? "global" : "local";
939
- const folderPath = project.dataPath;
940
- if (fs7.existsSync(folderPath)) {
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 (referenceFolderPaths.length > 0) {
963
- const readonlyPatterns = {};
964
- for (const folderPath of referenceFolderPaths) {
965
- readonlyPatterns[`${folderPath}/**`] = true;
966
- }
967
- const existingReadonly = workspace.settings["files.readonlyInclude"] || {};
968
- const cleanedReadonly = {};
969
- for (const [pattern, value] of Object.entries(existingReadonly)) {
970
- if (!pattern.includes(".rrce-workflow") && !pattern.includes("rrce-workflow/workspaces")) {
971
- cleanedReadonly[pattern] = value;
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
- var init_vscode = __esm({
982
- "src/commands/wizard/vscode.ts"() {
983
- "use strict";
984
- init_paths();
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
- // src/mcp/config-utils.ts
1018
- function findProjectConfig(config, identifier) {
1019
- return config.projects.find((p) => {
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 ensureMCPGlobalPath() {
1060
- const workspaceRoot = detectWorkspaceRoot();
1061
- const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1062
- if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
1063
- const configPath = path9.join(workspaceRoot, ".rrce-workflow", "config.yaml");
1064
- if (fs8.existsSync(configPath)) {
1065
- const content = fs8.readFileSync(configPath, "utf-8");
1066
- const modeMatch = content.match(/mode:\s*(global|workspace)/);
1067
- if (modeMatch?.[1] === "workspace") {
1068
- return {
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 loadMCPConfig() {
1082
- const configPath = getMCPConfigPath();
1083
- if (!fs8.existsSync(configPath)) {
1084
- return { ...DEFAULT_MCP_CONFIG };
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 content = fs8.readFileSync(configPath, "utf-8");
1088
- return parseMCPConfig(content);
1089
- } catch {
1090
- return { ...DEFAULT_MCP_CONFIG };
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 saveMCPConfig(config) {
1094
- const configPath = getMCPConfigPath();
1095
- const dir = path9.dirname(configPath);
1096
- if (!fs8.existsSync(dir)) {
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 parsed = YAML.parse(content);
1105
- const config = {
1106
- server: {
1107
- port: parsed?.server?.port ?? DEFAULT_MCP_CONFIG.server.port,
1108
- autoStart: parsed?.server?.autoStart ?? DEFAULT_MCP_CONFIG.server.autoStart
1109
- },
1110
- defaults: {
1111
- includeNew: parsed?.defaults?.includeNew ?? DEFAULT_MCP_CONFIG.defaults.includeNew,
1112
- permissions: {
1113
- knowledge: parsed?.defaults?.permissions?.knowledge ?? DEFAULT_PERMISSIONS.knowledge,
1114
- tasks: parsed?.defaults?.permissions?.tasks ?? DEFAULT_PERMISSIONS.tasks,
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 serializeMCPConfig(config) {
1136
- const header = `# RRCE MCP Hub Configuration
1137
- # Manages which projects are exposed via MCP
1138
-
1139
- `;
1140
- return header + YAML.stringify(config, {
1141
- indent: 2,
1142
- lineWidth: 0
1143
- // No line wrapping
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
- } else {
1160
- config.projects.push({
1161
- name,
1162
- path: projectPath,
1163
- expose,
1164
- permissions: permissions ? { ...DEFAULT_PERMISSIONS, ...permissions } : { ...DEFAULT_PERMISSIONS },
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 removeProjectConfig(config, name) {
1171
- config.projects = config.projects.filter((p) => p.name !== name);
1172
- return config;
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 isProjectExposed(config, name, projectPath) {
1175
- const project = findProjectConfig(config, { name, path: projectPath });
1176
- if (project) {
1177
- return project.expose;
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 getProjectPermissions(config, name, projectPath) {
1182
- const project = findProjectConfig(config, { name, path: projectPath });
1183
- return project?.permissions ?? config.defaults.permissions;
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 cleanStaleProjects(config) {
1186
- const rrceHome = getEffectiveGlobalPath();
1187
- const globalWorkspacesDir = path9.join(rrceHome, "workspaces");
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
- var init_config = __esm({
1210
- "src/mcp/config.ts"() {
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
- init_paths();
1213
- init_types();
1214
- init_config_utils();
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-actions.ts
1219
- import * as fs9 from "fs";
1220
- import * as path10 from "path";
1221
- import pc4 from "picocolors";
1222
- import { note as note2 } from "@clack/prompts";
1223
- function createDirectoryStructure(dataPaths) {
1224
- for (const dataPath of dataPaths) {
1225
- ensureDir(dataPath);
1226
- ensureDir(path10.join(dataPath, "knowledge"));
1227
- ensureDir(path10.join(dataPath, "refs"));
1228
- ensureDir(path10.join(dataPath, "tasks"));
1229
- ensureDir(path10.join(dataPath, "templates"));
1230
- }
1231
- }
1232
- function installAgentPrompts(config, workspacePath, dataPaths) {
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 createWorkspaceConfig(config, workspacePath, workspaceName) {
1252
- let configPath;
1253
- if (config.storageMode === "global") {
1254
- const rrceHome = config.globalPath || getDefaultRRCEHome2();
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
- ensureDir(path10.dirname(configPath));
1260
- let content = `# RRCE-Workflow Configuration
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
- content += `
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 (config.linkedProjects.length > 0) {
1286
- content += `
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
- fs9.writeFileSync(configPath, content);
1295
- }
1296
- async function registerWithMCP(config, workspacePath, workspaceName) {
1297
- if (!config.exposeToMCP) return;
1298
- try {
1299
- const { loadMCPConfig: loadMCPConfig3, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
1300
- const mcpConfig = loadMCPConfig3();
1301
- setProjectConfig2(
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 getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
1321
- const globalPath = path10.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
1322
- const workspacePath = path10.join(workspaceRoot, ".rrce-workflow");
1323
- switch (mode) {
1324
- case "global":
1325
- return [globalPath];
1326
- case "workspace":
1327
- return [workspacePath];
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
- var init_setup_actions = __esm({
1333
- "src/commands/wizard/setup-actions.ts"() {
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
- init_paths();
1336
- init_prompts();
1337
- init_utils();
1338
- init_vscode();
1150
+ init_install();
1339
1151
  }
1340
1152
  });
1341
1153
 
1342
- // src/commands/wizard/gitignore.ts
1343
- var gitignore_exports = {};
1344
- __export(gitignore_exports, {
1345
- updateGitignore: () => updateGitignore
1346
- });
1347
- import * as fs10 from "fs";
1348
- import * as path11 from "path";
1349
- function updateGitignore(workspacePath, storageMode, tools) {
1350
- const gitignorePath = path11.join(workspacePath, ".gitignore");
1351
- const entries = [];
1352
- if (storageMode === "workspace") {
1353
- entries.push(".rrce-workflow/");
1354
- }
1355
- if (tools.includes("copilot")) {
1356
- entries.push(".github/agents/");
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
- if (tools.includes("antigravity")) {
1359
- entries.push(".agent/workflows/");
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
- entries.push("*.code-workspace");
1362
- if (entries.length === 0) {
1363
- return false;
1204
+ }
1205
+ function loadPromptsFromDir(dirPath) {
1206
+ if (!fs6.existsSync(dirPath)) {
1207
+ return [];
1364
1208
  }
1365
- let existingContent = "";
1366
- if (fs10.existsSync(gitignorePath)) {
1367
- existingContent = fs10.readFileSync(gitignorePath, "utf-8");
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
- const sectionMarker = "# RRCE-Workflow Generated";
1370
- if (existingContent.includes(sectionMarker)) {
1371
- return false;
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
- const newSection = `
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
- var init_gitignore = __esm({
1383
- "src/commands/wizard/gitignore.ts"() {
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/mcp/logger.ts
1389
- import * as fs11 from "fs";
1390
- import * as path12 from "path";
1391
- function getLogFilePath() {
1392
- const workspaceRoot = detectWorkspaceRoot();
1393
- const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1394
- return path12.join(rrceHome, "mcp-server.log");
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
- var Logger, logger;
1397
- var init_logger = __esm({
1398
- "src/mcp/logger.ts"() {
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/mcp/services/rag.ts
1453
- import * as fs12 from "fs";
1454
- import * as path13 from "path";
1455
- var INDEX_VERSION, DEFAULT_MODEL, RAGService;
1456
- var init_rag = __esm({
1457
- "src/mcp/services/rag.ts"() {
1458
- "use strict";
1459
- init_logger();
1460
- INDEX_VERSION = "1.0.0";
1461
- DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
1462
- RAGService = class _RAGService {
1463
- // Static cache for the pipeline to prevent reloading model for every instance
1464
- static pipelineInstance = null;
1465
- static activeModelName = null;
1466
- static loadPromise = null;
1467
- modelName;
1468
- indexPath;
1469
- index = null;
1470
- constructor(indexPath, modelName = DEFAULT_MODEL) {
1471
- this.indexPath = indexPath;
1472
- this.modelName = modelName;
1473
- }
1474
- /**
1475
- * Lazy load the model (Singleton pattern)
1476
- */
1477
- async getPipeline() {
1478
- if (_RAGService.activeModelName === this.modelName && _RAGService.pipelineInstance) {
1479
- return _RAGService.pipelineInstance;
1480
- }
1481
- if (_RAGService.activeModelName === this.modelName && _RAGService.loadPromise) {
1482
- return _RAGService.loadPromise;
1483
- }
1484
- logger.info(`RAG: Initializing model ${this.modelName}...`);
1485
- _RAGService.activeModelName = this.modelName;
1486
- _RAGService.loadPromise = (async () => {
1487
- try {
1488
- const { pipeline } = await import("@xenova/transformers");
1489
- const pipe = await pipeline("feature-extraction", this.modelName);
1490
- _RAGService.pipelineInstance = pipe;
1491
- logger.info(`RAG: Model ${this.modelName} initialized successfully.`);
1492
- return pipe;
1493
- } catch (error) {
1494
- logger.error(`RAG: Failed to initialize model ${this.modelName}`, error);
1495
- _RAGService.pipelineInstance = null;
1496
- _RAGService.activeModelName = null;
1497
- _RAGService.loadPromise = null;
1498
- throw error;
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
- * Generate embedding for text
1548
- */
1549
- async generateEmbedding(text2) {
1550
- const pipe = await this.getPipeline();
1551
- try {
1552
- const output = await pipe(text2, { pooling: "mean", normalize: true });
1553
- return Array.from(output.data);
1554
- } catch (error) {
1555
- logger.error("RAG: Error generating embedding", error);
1556
- throw error;
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
- * Index a file (smart: skips if mtime unchanged)
1561
- * @param filePath Absolute path to the file
1562
- * @param content File content
1563
- * @param mtime Optional modification time (if not provided, always re-indexes)
1564
- * @returns true if file was indexed, false if skipped
1565
- */
1566
- async indexFile(filePath, content, mtime) {
1567
- this.loadIndex();
1568
- if (!this.index) throw new Error("Index not initialized");
1569
- if (!this.index.fileMetadata) {
1570
- this.index.fileMetadata = {};
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
- * Remove a file from index
1601
- */
1602
- async removeFile(filePath) {
1603
- this.loadIndex();
1604
- if (!this.index) return;
1605
- const initialCount = this.index.chunks.length;
1606
- this.index.chunks = this.index.chunks.filter((c) => c.filePath !== filePath);
1607
- if (this.index.fileMetadata) {
1608
- delete this.index.fileMetadata[filePath];
1609
- }
1610
- if (this.index.chunks.length !== initialCount) {
1611
- logger.info(`RAG: Removed file ${filePath} from index (${initialCount - this.index.chunks.length} chunks removed)`);
1612
- this.saveIndex();
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
- * Get index statistics
1617
- */
1618
- getStats() {
1619
- this.loadIndex();
1620
- if (!this.index) return { totalChunks: 0, totalFiles: 0 };
1621
- const fileCount = this.index.fileMetadata ? Object.keys(this.index.fileMetadata).length : 0;
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
- totalChunks: this.index.chunks.length,
1624
- totalFiles: fileCount,
1625
- lastFullIndex: this.index.lastFullIndex
1443
+ configured: false,
1444
+ path: rrceHome,
1445
+ reason: "Workspace mode configured. MCP requires a global storage path."
1626
1446
  };
1627
1447
  }
1628
- /**
1629
- * Mark the last full index timestamp
1630
- */
1631
- markFullIndex() {
1632
- this.loadIndex();
1633
- if (!this.index) return;
1634
- this.index.lastFullIndex = Date.now();
1635
- this.saveIndex();
1636
- }
1637
- /**
1638
- * Search the index
1639
- */
1640
- async search(query, limit = 5) {
1641
- this.loadIndex();
1642
- if (!this.index || this.index.chunks.length === 0) {
1643
- logger.warn("RAG: Search called on empty index");
1644
- return [];
1645
- }
1646
- logger.info(`RAG: Searching for "${query}" (limit: ${limit})`);
1647
- const queryEmbedding = await this.generateEmbedding(query);
1648
- const results = this.index.chunks.map((chunk) => {
1649
- const score = this.cosineSimilarity(queryEmbedding, chunk.embedding);
1650
- return { ...chunk, score };
1651
- });
1652
- results.sort((a, b) => b.score - a.score);
1653
- const topResults = results.slice(0, limit);
1654
- logger.info(`RAG: Search returned ${topResults.length} matches. Top score: ${topResults[0]?.score.toFixed(4)}`);
1655
- return topResults;
1656
- }
1657
- /**
1658
- * Simple cosine similarity
1659
- */
1660
- cosineSimilarity(a, b) {
1661
- let dotProduct = 0;
1662
- let normA = 0;
1663
- let normB = 0;
1664
- for (let i = 0; i < a.length; i++) {
1665
- dotProduct += a[i] * b[i];
1666
- normA += a[i] * a[i];
1667
- normB += b[i] * b[i];
1668
- }
1669
- return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
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
- return chunks;
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
- // src/mcp/resources.ts
1701
- import * as fs13 from "fs";
1702
- import * as path14 from "path";
1703
- function getExposedProjects() {
1704
- const config = loadMCPConfig();
1705
- const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
1706
- const allProjects = projectService.scan({ knownPaths });
1707
- const globalProjects = allProjects.filter((project) => isProjectExposed(config, project.name, project.dataPath));
1708
- const activeProject = detectActiveProject(globalProjects);
1709
- let linkedProjects = [];
1710
- if (activeProject) {
1711
- const localConfigPath = path14.join(activeProject.dataPath, "config.yaml");
1712
- let cfgContent = null;
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 (cfgContent) {
1719
- if (cfgContent.includes("linked_projects:")) {
1720
- const lines = cfgContent.split("\n");
1721
- let inLinked = false;
1722
- for (const line of lines) {
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 [...globalProjects, ...linkedProjects];
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 detectActiveProject(knownProjects) {
1755
- let scanList = knownProjects;
1756
- if (!scanList) {
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 getProjectContext(projectName) {
1765
- const config = loadMCPConfig();
1766
- const projects = projectService.scan();
1767
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
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 fs13.readFileSync(contextPath, "utf-8");
1553
+ return config.defaults.includeNew;
1783
1554
  }
1784
- function getProjectTasks(projectName) {
1785
- const config = loadMCPConfig();
1786
- const projects = projectService.scan();
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
- async function searchKnowledge(query) {
1817
- const config = loadMCPConfig();
1818
- const projects = getExposedProjects();
1819
- const results = [];
1820
- const queryLower = query.toLowerCase();
1821
- for (const project of projects) {
1822
- const permissions = getProjectPermissions(config, project.name, project.dataPath);
1823
- if (!permissions.knowledge || !project.knowledgePath) continue;
1824
- const projConfig = config.projects.find(
1825
- (p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
1826
- );
1827
- const useRAG = projConfig?.semanticSearch?.enabled;
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
- try {
1847
- const files = fs13.readdirSync(project.knowledgePath);
1848
- for (const file of files) {
1849
- if (!file.endsWith(".md")) continue;
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
- return results;
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
- const projConfig = config.projects.find(
1881
- (p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
1882
- ) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
1883
- const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
1884
- if (!isEnabled) {
1885
- return { success: false, message: "Semantic Search is not enabled for this project", filesIndexed: 0, filesSkipped: 0 };
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
- const scanRoot = project.sourcePath || project.path || project.dataPath;
1888
- if (!fs13.existsSync(scanRoot)) {
1889
- return { success: false, message: "Project root not found", filesIndexed: 0, filesSkipped: 0 };
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
- const INDEXABLE_EXTENSIONS = [
1892
- ".ts",
1893
- ".tsx",
1894
- ".js",
1895
- ".jsx",
1896
- ".mjs",
1897
- ".cjs",
1898
- ".py",
1899
- ".pyw",
1900
- ".go",
1901
- ".rs",
1902
- ".java",
1903
- ".kt",
1904
- ".kts",
1905
- ".c",
1906
- ".cpp",
1907
- ".h",
1908
- ".hpp",
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 getContextPreamble() {
1979
- const projects = getExposedProjects();
1980
- const activeProject = detectActiveProject();
1981
- const projectList = projects.map((p) => {
1982
- const isActive = activeProject && p.dataPath === activeProject.dataPath;
1983
- return `- ${p.name} (${p.source}) ${isActive ? "**[ACTIVE]**" : ""}`;
1984
- }).join("\n");
1985
- let contextPreamble = `
1986
- Context - Available Projects (MCP Hub):
1987
- ${projectList}
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 (projects.length === 0) {
1990
- contextPreamble += `
1991
- WARNING: No projects are currently exposed to the MCP server.
1992
- The user needs to run 'npx rrce-workflow mcp configure' in their terminal to select projects to expose.
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 (activeProject) {
1997
- contextPreamble += `
1998
- Current Active Workspace: ${activeProject.name} (${activeProject.path})
1660
+ if (config.linkedProjects.length > 0) {
1661
+ content += `
1662
+ linked_projects:
1999
1663
  `;
2000
- contextPreamble += `IMPORTANT: Treat '${activeProject.path}' as the {{WORKSPACE_ROOT}}. All relative path operations (file reads/writes) MUST be performed relative to this directory.
1664
+ config.linkedProjects.forEach((name) => {
1665
+ content += ` - ${name}
2001
1666
  `;
1667
+ });
2002
1668
  }
2003
- contextPreamble += `
2004
- Note: If the user's request refers to a project not listed here, ask them to expose it via 'rrce-workflow mcp configure'.
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
- return contextPreamble;
1690
+ You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
1691
+ "MCP Registration Warning"
1692
+ );
1693
+ }
2009
1694
  }
2010
- var init_resources = __esm({
2011
- "src/mcp/resources.ts"() {
2012
- "use strict";
2013
- init_config();
2014
- init_detection();
2015
- init_detection_service();
2016
- init_rag();
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
- // src/mcp/handlers/resources.ts
2021
- import "@modelcontextprotocol/sdk/server/index.js";
2022
- import {
2023
- ListResourcesRequestSchema,
2024
- ReadResourceRequestSchema
2025
- } from "@modelcontextprotocol/sdk/types.js";
2026
- function registerResourceHandlers(server) {
2027
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
2028
- logger.debug("Listing resources");
2029
- const projects = getExposedProjects();
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
- if (uri === "rrce://projects") {
2064
- const projects = getExposedProjects();
2065
- return {
2066
- contents: [{
2067
- uri,
2068
- mimeType: "application/json",
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
- logger.error(`Failed to read resource: ${uri}`, error);
2090
- throw error;
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 init_resources2 = __esm({
2095
- "src/mcp/handlers/resources.ts"() {
1734
+ var init_setup_actions = __esm({
1735
+ "src/commands/wizard/setup-actions.ts"() {
2096
1736
  "use strict";
2097
- init_logger();
2098
- init_config();
2099
- init_resources();
1737
+ init_paths();
1738
+ init_prompts();
1739
+ init_utils();
1740
+ init_vscode();
1741
+ init_install();
2100
1742
  }
2101
1743
  });
2102
1744
 
2103
- // src/mcp/prompts.ts
2104
- function getAllPrompts() {
2105
- const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
2106
- return prompts.map((p) => {
2107
- const args = [];
2108
- if (p.frontmatter["required-args"]) {
2109
- args.push(...p.frontmatter["required-args"].map((a) => ({
2110
- name: a.name,
2111
- description: a.prompt || a.name,
2112
- required: true
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
- return rendered;
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 init_prompts2 = __esm({
2148
- "src/mcp/prompts.ts"() {
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/handlers/tools.ts
2155
- import "@modelcontextprotocol/sdk/server/index.js";
2156
- import {
2157
- ListToolsRequestSchema,
2158
- CallToolRequestSchema
2159
- } from "@modelcontextprotocol/sdk/types.js";
2160
- function registerToolHandlers(server) {
2161
- server.setRequestHandler(ListToolsRequestSchema, async () => {
2162
- const tools = [
2163
- {
2164
- name: "search_knowledge",
2165
- description: "Search across all exposed project knowledge bases",
2166
- inputSchema: {
2167
- type: "object",
2168
- properties: { query: { type: "string", description: "Search query to find in knowledge files" } },
2169
- required: ["query"]
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
- name: "index_knowledge",
2174
- description: "Update the semantic search index for a specific project",
2175
- inputSchema: {
2176
- type: "object",
2177
- properties: {
2178
- project: { type: "string", description: "Name of the project to index" },
2179
- force: { type: "boolean", description: "Force re-indexing of all files" }
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
- name: "list_projects",
2186
- description: "List all projects exposed via MCP. Use these names for project-specific tools.",
2187
- inputSchema: { type: "object", properties: {} }
2188
- },
2189
- {
2190
- name: "get_project_context",
2191
- description: "Get the project context/architecture for a specific project",
2192
- inputSchema: {
2193
- type: "object",
2194
- properties: { project: { type: "string", description: "Name of the project to get context for" } },
2195
- required: ["project"]
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
- const projects = getExposedProjects();
2217
- if (projects.length === 0) {
2218
- tools.push({
2219
- name: "help_setup",
2220
- description: "Get help on how to configure projects for the RRCE MCP Server",
2221
- inputSchema: { type: "object", properties: {} }
2222
- });
2223
- }
2224
- return { tools };
2225
- });
2226
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
2227
- const { name, arguments: args } = request.params;
2228
- logger.info(`Calling tool: ${name}`, args);
2229
- try {
2230
- switch (name) {
2231
- case "search_knowledge": {
2232
- const results = await searchKnowledge(args.query);
2233
- return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
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
- case "index_knowledge": {
2236
- const params = args;
2237
- const result = await indexKnowledge(params.project, params.force);
2238
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
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
- case "list_projects": {
2241
- const projects = getExposedProjects();
2242
- const list = projects.map((p) => ({ name: p.name, source: p.source, path: p.path }));
2243
- return {
2244
- content: [{
2245
- type: "text",
2246
- text: JSON.stringify(list, null, 2) + "\n\nTip: Use these project names for tools like `get_project_context` or `index_knowledge`."
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
- case "get_project_context": {
2251
- const context = getProjectContext(args.project);
2252
- if (!context) {
2253
- const projects = getExposedProjects().map((p) => p.name).join(", ");
2254
- const msg = `No project context found for "${args.project}".
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
- case "list_agents": {
2262
- const prompts = getAllPrompts();
2263
- return {
2264
- content: [{
2265
- type: "text",
2266
- text: JSON.stringify(prompts.map((p) => ({
2267
- name: p.name,
2268
- id: p.id,
2269
- description: p.description,
2270
- arguments: p.arguments
2271
- })), null, 2) + "\n\nTip: Retrieve the prompt for an agent using `get_agent_prompt` with its name or ID."
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
- case "get_agent_prompt": {
2276
- const params = args;
2277
- const agentName = params.agent;
2278
- const promptDef = getPromptDef(agentName);
2279
- if (!promptDef) {
2280
- const available = getAllPrompts().map((p) => `${p.name} (id: ${p.id})`).join(", ");
2281
- throw new Error(`Agent not found: ${agentName}. Available agents: ${available}`);
2282
- }
2283
- const renderArgs = params.args || {};
2284
- const stringArgs = {};
2285
- for (const [key, val] of Object.entries(renderArgs)) {
2286
- stringArgs[key] = String(val);
2287
- }
2288
- const content = renderPrompt(promptDef.content, stringArgs);
2289
- const contextPreamble = getContextPreamble();
2290
- return { content: [{ type: "text", text: contextPreamble + content }] };
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
- case "help_setup": {
2293
- const msg = `
2294
- RRCE MCP Server is running, but no projects are configured/exposed.
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
- } catch (error) {
2308
- logger.error(`Tool execution failed: ${name}`, error);
2309
- throw error;
2310
- }
2311
- });
2312
- }
2313
- var init_tools = __esm({
2314
- "src/mcp/handlers/tools.ts"() {
2315
- "use strict";
2316
- init_logger();
2317
- init_resources();
2318
- init_prompts2();
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
- const renderArgs = {};
2360
- for (const [key, val] of Object.entries(providedArgs)) {
2361
- renderArgs[key] = String(val);
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
- const activeProject = detectActiveProject();
2364
- const DEFAULT_RRCE_HOME = getEffectiveGlobalPath();
2365
- let resolvedRrceData = ".rrce-workflow/";
2366
- let resolvedRrceHome = DEFAULT_RRCE_HOME;
2367
- let resolvedWorkspaceRoot = process.cwd();
2368
- let resolvedWorkspaceName = "current-project";
2369
- if (activeProject) {
2370
- resolvedRrceData = activeProject.dataPath + "/";
2371
- resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
2372
- resolvedWorkspaceName = activeProject.name;
2373
- if (activeProject.source === "global") {
2374
- const workspacesDir = path15.dirname(activeProject.dataPath);
2375
- resolvedRrceHome = path15.dirname(workspacesDir);
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
- if (!renderArgs["RRCE_DATA"]) renderArgs["RRCE_DATA"] = resolvedRrceData;
2379
- if (!renderArgs["RRCE_HOME"]) renderArgs["RRCE_HOME"] = resolvedRrceHome;
2380
- if (!renderArgs["WORKSPACE_ROOT"]) renderArgs["WORKSPACE_ROOT"] = resolvedWorkspaceRoot;
2381
- if (!renderArgs["WORKSPACE_NAME"]) renderArgs["WORKSPACE_NAME"] = resolvedWorkspaceName;
2382
- const content = renderPrompt(promptDef.content, renderArgs);
2383
- let contextPreamble = getContextPreamble();
2384
- contextPreamble += `
2385
- ### System Resolved Paths (OVERRIDE)
2386
- The system has pre-resolved the configuration for this project. Use these values instead of manual resolution:
2387
- - **RRCE_DATA**: \`${resolvedRrceData}\` (Stores knowledge, tasks, refs)
2388
- - **WORKSPACE_ROOT**: \`${resolvedWorkspaceRoot}\` (Source code location)
2389
- - **RRCE_HOME**: \`${resolvedRrceHome}\`
2390
- - **Current Project**: ${resolvedWorkspaceName}
2391
- `;
2392
- return {
2393
- messages: [
2394
- {
2395
- role: "user",
2396
- content: {
2397
- type: "text",
2398
- text: contextPreamble + content
2399
- }
2400
- }
2401
- ]
2402
- };
2403
- } catch (error) {
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/server.ts
2420
- var server_exports = {};
2421
- __export(server_exports, {
2422
- getMCPServerStatus: () => getMCPServerStatus,
2423
- startMCPServer: () => startMCPServer,
2424
- stopMCPServer: () => stopMCPServer
2425
- });
2426
- import { Server as Server4 } from "@modelcontextprotocol/sdk/server/index.js";
2427
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2428
- async function startMCPServer(options = {}) {
2429
- try {
2430
- logger.info("Starting MCP Server...");
2431
- process.on("uncaughtException", (error) => {
2432
- logger.error("Uncaught Exception", error);
2433
- console.error("Uncaught Exception:", error);
2434
- });
2435
- process.on("unhandledRejection", (reason) => {
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
- serverState = { running: true, port: config.server.port, pid: process.pid };
2457
- const exposed = getExposedProjects().map((p) => p.name).join(", ");
2458
- logger.info(`RRCE MCP Hub started (pid: ${process.pid})`, { exposedProjects: exposed });
2459
- if (!options.interactive) {
2460
- console.error(`RRCE MCP Hub started (pid: ${process.pid})`);
2461
- console.error(`Exposed projects: ${exposed}`);
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
- serverState = { running: false };
2476
- logger.info("RRCE MCP Hub stopped");
2151
+ return [...globalProjects, ...linkedProjects];
2477
2152
  }
2478
- function getMCPServerStatus() {
2479
- return { ...serverState };
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
- var serverState, mcpServer;
2482
- var init_server = __esm({
2483
- "src/mcp/server.ts"() {
2484
- "use strict";
2485
- init_logger();
2486
- init_config();
2487
- init_resources();
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 checkAntigravityConfig() {
2510
- if (!fs14.existsSync(ANTIGRAVITY_CONFIG)) return false;
2511
- try {
2512
- const content = JSON.parse(fs14.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
2513
- return !!content.mcpServers?.["rrce"];
2514
- } catch {
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
- function checkClaudeConfig() {
2519
- if (!fs14.existsSync(CLAUDE_CONFIG)) return false;
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
- function checkVSCodeGlobalConfig() {
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
- function checkVSCodeWorkspaceConfig(workspacePath) {
2537
- const configPath = path16.join(workspacePath, ".vscode", "mcp.json");
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 checkOpenCodeConfig() {
2547
- if (!fs14.existsSync(OPENCODE_CONFIG)) return false;
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 content = JSON.parse(fs14.readFileSync(OPENCODE_CONFIG, "utf-8"));
2550
- return !!content.mcp?.["rrce"];
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 installToAntigravity() {
2576
- const dir = path16.dirname(ANTIGRAVITY_CONFIG);
2577
- if (!fs14.existsSync(dir)) {
2578
- fs14.mkdirSync(dir, { recursive: true });
2579
- }
2580
- let config = { mcpServers: {} };
2581
- if (fs14.existsSync(ANTIGRAVITY_CONFIG)) {
2582
- try {
2583
- config = JSON.parse(fs14.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
2584
- } catch {
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
- config = JSON.parse(fs14.readFileSync(CLAUDE_CONFIG, "utf-8"));
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
- if (!config.mcpServers) config.mcpServers = {};
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 installToVSCodeGlobal() {
2624
- const dir = path16.dirname(VSCODE_GLOBAL_CONFIG);
2625
- if (!fs14.existsSync(dir)) {
2626
- fs14.mkdirSync(dir, { recursive: true });
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
- let settings = {};
2629
- if (fs14.existsSync(VSCODE_GLOBAL_CONFIG)) {
2630
- try {
2631
- settings = JSON.parse(fs14.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
2632
- } catch {
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
- if (!settings["mcp.servers"]) settings["mcp.servers"] = {};
2636
- settings["mcp.servers"]["rrce"] = {
2637
- command: "npx",
2638
- args: ["-y", "rrce-workflow", "mcp", "start"]
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
- fs14.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
2642
- return true;
2643
- } catch {
2644
- return false;
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 installToVSCodeWorkspace(workspacePath) {
2648
- const vscodeDir = path16.join(workspacePath, ".vscode");
2649
- const configPath = path16.join(vscodeDir, "mcp.json");
2650
- if (!fs14.existsSync(vscodeDir)) {
2651
- fs14.mkdirSync(vscodeDir, { recursive: true });
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
- let config = { servers: {} };
2654
- if (fs14.existsSync(configPath)) {
2655
- try {
2656
- config = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
2657
- } catch {
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 (!config.servers) config.servers = {};
2661
- config.servers["rrce"] = {
2662
- command: "npx",
2663
- args: ["-y", "rrce-workflow", "mcp", "start"]
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
- function installToOpenCode() {
2673
- const dir = path16.dirname(OPENCODE_CONFIG);
2674
- if (!fs14.existsSync(dir)) {
2675
- fs14.mkdirSync(dir, { recursive: true });
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
- let config = {
2678
- $schema: "https://opencode.ai/config.json"
2679
- };
2680
- if (fs14.existsSync(OPENCODE_CONFIG)) {
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
- config = JSON.parse(fs14.readFileSync(OPENCODE_CONFIG, "utf-8"));
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
- console.error("Warning: Could not parse existing OpenCode config, creating fresh config");
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
- function uninstallFromOpenCode() {
2702
- if (!fs14.existsSync(OPENCODE_CONFIG)) {
2703
- console.error("OpenCode config not found");
2704
- return false;
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
- try {
2707
- const config = JSON.parse(fs14.readFileSync(OPENCODE_CONFIG, "utf-8"));
2708
- if (!config.mcp?.["rrce"]) {
2709
- console.warn("RRCE not found in OpenCode config");
2710
- return false;
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
- delete config.mcp["rrce"];
2713
- fs14.writeFileSync(OPENCODE_CONFIG, JSON.stringify(config, null, 2) + "\n");
2714
- return true;
2715
- } catch (error) {
2716
- console.error("Failed to uninstall from OpenCode:", error instanceof Error ? error.message : String(error));
2717
- return false;
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
- function uninstallFromAntigravity() {
2721
- if (!fs14.existsSync(ANTIGRAVITY_CONFIG)) {
2722
- console.error("Antigravity config not found");
2723
- return false;
2565
+ var init_prompts2 = __esm({
2566
+ "src/mcp/prompts.ts"() {
2567
+ "use strict";
2568
+ init_prompts();
2724
2569
  }
2725
- try {
2726
- const config = JSON.parse(fs14.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
2727
- if (!config.mcpServers?.["rrce"]) {
2728
- console.warn("RRCE not found in Antigravity config");
2729
- return false;
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
- delete config.mcpServers["rrce"];
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
- function uninstallFromClaude() {
2740
- if (!fs14.existsSync(CLAUDE_CONFIG)) {
2741
- console.error("Claude Desktop config not found");
2742
- return false;
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
- try {
2745
- const config = JSON.parse(fs14.readFileSync(CLAUDE_CONFIG, "utf-8"));
2746
- if (!config.mcpServers?.["rrce"]) {
2747
- console.warn("RRCE not found in Claude Desktop config");
2748
- return false;
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
- delete config.mcpServers["rrce"];
2751
- fs14.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2) + "\n");
2752
- return true;
2753
- } catch (error) {
2754
- console.error("Failed to uninstall from Claude Desktop:", error instanceof Error ? error.message : String(error));
2755
- return false;
2756
- }
2757
- }
2758
- function uninstallFromVSCodeGlobal() {
2759
- if (!fs14.existsSync(VSCODE_GLOBAL_CONFIG)) {
2760
- console.error("VSCode global config not found");
2761
- return false;
2762
- }
2763
- try {
2764
- const settings = JSON.parse(fs14.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
2765
- if (!settings["mcp.servers"]?.["rrce"]) {
2766
- console.warn("RRCE not found in VSCode global settings");
2767
- return false;
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
- delete settings["mcp.servers"]["rrce"];
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
- function uninstallFromVSCodeWorkspace(workspacePath) {
2778
- const configPath = path16.join(workspacePath, ".vscode", "mcp.json");
2779
- if (!fs14.existsSync(configPath)) {
2780
- console.error("VSCode workspace config not found");
2781
- return false;
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
- const config = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
2785
- if (!config.servers?.["rrce"]) {
2786
- console.warn("RRCE not found in VSCode workspace config");
2787
- return false;
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
- delete config.servers["rrce"];
2790
- fs14.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
2791
- return true;
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
- console.error("Failed to uninstall from VSCode (Workspace):", error instanceof Error ? error.message : String(error));
2794
- return false;
2887
+ logger.error("Failed to start MCP server", error);
2888
+ throw error;
2795
2889
  }
2796
2890
  }
2797
- function uninstallFromConfig(target, workspacePath) {
2798
- switch (target) {
2799
- case "antigravity":
2800
- return uninstallFromAntigravity();
2801
- case "claude":
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 getTargetLabel(target) {
2814
- switch (target) {
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 ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG, OPENCODE_CONFIG;
2830
- var init_install = __esm({
2831
- "src/mcp/install.ts"() {
2903
+ var serverState, mcpServer;
2904
+ var init_server = __esm({
2905
+ "src/mcp/server.ts"() {
2832
2906
  "use strict";
2833
- ANTIGRAVITY_CONFIG = path16.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
2834
- CLAUDE_CONFIG = path16.join(os.homedir(), ".config/claude/claude_desktop_config.json");
2835
- VSCODE_GLOBAL_CONFIG = path16.join(os.homedir(), ".config/Code/User/settings.json");
2836
- OPENCODE_CONFIG = path16.join(os.homedir(), ".config/opencode/opencode.json");
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: All available`,
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: ["copilot", "antigravity"],
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();