rrce-workflow 0.3.19 → 0.3.20

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
@@ -1646,9 +1646,434 @@ ${JSON.stringify(data, null, 2)}`;
1646
1646
  }
1647
1647
  });
1648
1648
 
1649
+ // src/mcp/resources/types.ts
1650
+ var init_types2 = __esm({
1651
+ "src/mcp/resources/types.ts"() {
1652
+ "use strict";
1653
+ }
1654
+ });
1655
+
1656
+ // src/mcp/resources/constants.ts
1657
+ var INDEXABLE_EXTENSIONS, CODE_EXTENSIONS, SKIP_DIRS;
1658
+ var init_constants = __esm({
1659
+ "src/mcp/resources/constants.ts"() {
1660
+ "use strict";
1661
+ INDEXABLE_EXTENSIONS = [
1662
+ ".ts",
1663
+ ".tsx",
1664
+ ".js",
1665
+ ".jsx",
1666
+ ".mjs",
1667
+ ".cjs",
1668
+ ".py",
1669
+ ".pyw",
1670
+ ".go",
1671
+ ".rs",
1672
+ ".java",
1673
+ ".kt",
1674
+ ".kts",
1675
+ ".c",
1676
+ ".cpp",
1677
+ ".h",
1678
+ ".hpp",
1679
+ ".cs",
1680
+ ".rb",
1681
+ ".php",
1682
+ ".swift",
1683
+ ".md",
1684
+ ".mdx",
1685
+ ".json",
1686
+ ".yaml",
1687
+ ".yml",
1688
+ ".toml",
1689
+ ".sh",
1690
+ ".bash",
1691
+ ".zsh",
1692
+ ".sql",
1693
+ ".html",
1694
+ ".css",
1695
+ ".scss",
1696
+ ".sass",
1697
+ ".less"
1698
+ ];
1699
+ CODE_EXTENSIONS = [
1700
+ ".ts",
1701
+ ".tsx",
1702
+ ".js",
1703
+ ".jsx",
1704
+ ".mjs",
1705
+ ".cjs",
1706
+ ".py",
1707
+ ".pyw",
1708
+ ".go",
1709
+ ".rs",
1710
+ ".java",
1711
+ ".kt",
1712
+ ".kts",
1713
+ ".c",
1714
+ ".cpp",
1715
+ ".h",
1716
+ ".hpp",
1717
+ ".cs",
1718
+ ".rb",
1719
+ ".php",
1720
+ ".swift",
1721
+ ".sh",
1722
+ ".bash",
1723
+ ".zsh",
1724
+ ".sql"
1725
+ ];
1726
+ SKIP_DIRS = [
1727
+ "node_modules",
1728
+ ".git",
1729
+ "dist",
1730
+ "build",
1731
+ ".next",
1732
+ "__pycache__",
1733
+ "venv",
1734
+ ".venv",
1735
+ "target",
1736
+ "vendor"
1737
+ ];
1738
+ }
1739
+ });
1740
+
1741
+ // src/mcp/resources/utils.ts
1742
+ import * as fs13 from "fs";
1743
+ import * as path15 from "path";
1744
+ import ignore from "ignore";
1745
+ function estimateTokens(text2) {
1746
+ return Math.ceil(text2.length / 4);
1747
+ }
1748
+ function getScanContext(project, scanRoot) {
1749
+ const gitignorePath = path15.join(scanRoot, ".gitignore");
1750
+ const ig = fs13.existsSync(gitignorePath) ? ignore().add(fs13.readFileSync(gitignorePath, "utf-8")) : null;
1751
+ const toPosixRelativePath = (absolutePath) => {
1752
+ const rel = path15.relative(scanRoot, absolutePath);
1753
+ return rel.split(path15.sep).join("/");
1754
+ };
1755
+ const isUnderGitDir = (absolutePath) => {
1756
+ const rel = toPosixRelativePath(absolutePath);
1757
+ return rel === ".git" || rel.startsWith(".git/");
1758
+ };
1759
+ const isIgnoredByGitignore = (absolutePath, isDir) => {
1760
+ if (!ig) return false;
1761
+ const rel = toPosixRelativePath(absolutePath);
1762
+ return ig.ignores(isDir ? `${rel}/` : rel);
1763
+ };
1764
+ const shouldSkipEntryDir = (absolutePath) => {
1765
+ const dirName = path15.basename(absolutePath);
1766
+ if (dirName === ".git") return true;
1767
+ if (SKIP_DIRS.includes(dirName)) return true;
1768
+ if (isIgnoredByGitignore(absolutePath, true)) return true;
1769
+ return false;
1770
+ };
1771
+ const shouldSkipEntryFile = (absolutePath) => {
1772
+ if (isUnderGitDir(absolutePath)) return true;
1773
+ if (isIgnoredByGitignore(absolutePath, false)) return true;
1774
+ return false;
1775
+ };
1776
+ return { shouldSkipEntryDir, shouldSkipEntryFile };
1777
+ }
1778
+ var init_utils2 = __esm({
1779
+ "src/mcp/resources/utils.ts"() {
1780
+ "use strict";
1781
+ init_constants();
1782
+ }
1783
+ });
1784
+
1785
+ // src/mcp/resources/paths.ts
1786
+ import * as fs14 from "fs";
1787
+ function resolveProjectPaths(project, pathInput) {
1788
+ const config = loadMCPConfig();
1789
+ let workspaceRoot = pathInput;
1790
+ let workspaceName = project;
1791
+ if (!workspaceRoot && project) {
1792
+ const projConfig = findProjectConfig(config, { name: project });
1793
+ if (projConfig?.path) {
1794
+ workspaceRoot = projConfig.path;
1795
+ }
1796
+ }
1797
+ if (!workspaceName && workspaceRoot) {
1798
+ const projConfig = findProjectConfig(config, { path: workspaceRoot });
1799
+ workspaceName = projConfig?.name || getWorkspaceName(workspaceRoot);
1800
+ }
1801
+ if (!workspaceName) {
1802
+ workspaceName = "unknown";
1803
+ }
1804
+ let rrceData = "";
1805
+ let mode = "global";
1806
+ let configFilePath = "";
1807
+ if (workspaceRoot) {
1808
+ configFilePath = getConfigPath(workspaceRoot);
1809
+ const rrceHome = getEffectiveGlobalPath();
1810
+ if (configFilePath.startsWith(rrceHome)) {
1811
+ mode = "global";
1812
+ } else {
1813
+ mode = "workspace";
1814
+ if (fs14.existsSync(configFilePath)) {
1815
+ const content = fs14.readFileSync(configFilePath, "utf-8");
1816
+ if (content.includes("mode: global")) mode = "global";
1817
+ if (content.includes("mode: workspace")) mode = "workspace";
1818
+ }
1819
+ }
1820
+ rrceData = resolveDataPath(mode, workspaceName, workspaceRoot);
1821
+ } else {
1822
+ rrceData = resolveDataPath("global", workspaceName, "");
1823
+ }
1824
+ return {
1825
+ RRCE_HOME: getRRCEHome(),
1826
+ RRCE_DATA: rrceData,
1827
+ WORKSPACE_ROOT: workspaceRoot || null,
1828
+ WORKSPACE_NAME: workspaceName,
1829
+ storage_mode: mode,
1830
+ config_path: configFilePath || null
1831
+ };
1832
+ }
1833
+ var init_paths2 = __esm({
1834
+ "src/mcp/resources/paths.ts"() {
1835
+ "use strict";
1836
+ init_config();
1837
+ init_config_utils();
1838
+ init_paths();
1839
+ }
1840
+ });
1841
+
1842
+ // src/mcp/resources/projects.ts
1843
+ import * as fs15 from "fs";
1844
+ import * as path16 from "path";
1845
+ function getExposedProjects() {
1846
+ const config = loadMCPConfig();
1847
+ const knownProjects = config.projects.filter((p) => !!p.path).map((p) => ({ name: p.name, path: p.path }));
1848
+ const allProjects = projectService.scan({ knownProjects });
1849
+ const activeProject = detectActiveProject(allProjects);
1850
+ const potentialProjects = [...allProjects];
1851
+ if (activeProject) {
1852
+ let cfgContent = null;
1853
+ if (fs15.existsSync(path16.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
1854
+ cfgContent = fs15.readFileSync(path16.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
1855
+ } else if (fs15.existsSync(path16.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
1856
+ cfgContent = fs15.readFileSync(path16.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
1857
+ }
1858
+ if (cfgContent) {
1859
+ if (cfgContent.includes("linked_projects:")) {
1860
+ const lines = cfgContent.split("\n");
1861
+ let inLinked = false;
1862
+ for (const line of lines) {
1863
+ const trimmed = line.trim();
1864
+ if (trimmed.startsWith("linked_projects:")) {
1865
+ inLinked = true;
1866
+ continue;
1867
+ }
1868
+ if (inLinked) {
1869
+ if (trimmed.startsWith("-") || trimmed.startsWith("linked_projects")) {
1870
+ } else if (trimmed !== "" && !trimmed.startsWith("#")) {
1871
+ inLinked = false;
1872
+ }
1873
+ if (inLinked && trimmed.startsWith("-")) {
1874
+ const val = trimmed.replace(/^-\s*/, "").trim();
1875
+ const [pName] = val.split(":");
1876
+ if (!potentialProjects.some((p) => p.name === pName)) {
1877
+ const found = allProjects.find((p) => p.name === pName);
1878
+ if (found) {
1879
+ potentialProjects.push(found);
1880
+ }
1881
+ }
1882
+ }
1883
+ }
1884
+ }
1885
+ }
1886
+ }
1887
+ }
1888
+ return potentialProjects.filter((project) => isProjectExposed(config, project.name, project.sourcePath || project.path));
1889
+ }
1890
+ function detectActiveProject(knownProjects) {
1891
+ let scanList = knownProjects;
1892
+ if (!scanList) {
1893
+ const config = loadMCPConfig();
1894
+ const knownProjectsMap = config.projects.filter((p) => !!p.path).map((p) => ({ name: p.name, path: p.path }));
1895
+ const all = projectService.scan({ knownProjects: knownProjectsMap });
1896
+ scanList = all.filter((project) => isProjectExposed(config, project.name, project.sourcePath || project.path));
1897
+ }
1898
+ return findClosestProject(scanList);
1899
+ }
1900
+ function getProjectContext(projectName) {
1901
+ const config = loadMCPConfig();
1902
+ const projects = projectService.scan();
1903
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
1904
+ if (!project) {
1905
+ return null;
1906
+ }
1907
+ const permissions = getProjectPermissions(config, projectName, project.sourcePath || project.path);
1908
+ if (!permissions.knowledge) {
1909
+ return null;
1910
+ }
1911
+ if (!project.knowledgePath) {
1912
+ return null;
1913
+ }
1914
+ const contextPath = path16.join(project.knowledgePath, "project-context.md");
1915
+ if (!fs15.existsSync(contextPath)) {
1916
+ return null;
1917
+ }
1918
+ return fs15.readFileSync(contextPath, "utf-8");
1919
+ }
1920
+ function getCodeIndexPath(project) {
1921
+ const scanRoot = project.path || project.dataPath;
1922
+ return path16.join(project.knowledgePath || path16.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
1923
+ }
1924
+ var init_projects = __esm({
1925
+ "src/mcp/resources/projects.ts"() {
1926
+ "use strict";
1927
+ init_logger();
1928
+ init_config();
1929
+ init_detection();
1930
+ init_detection_service();
1931
+ }
1932
+ });
1933
+
1934
+ // src/mcp/resources/tasks.ts
1935
+ import * as fs16 from "fs";
1936
+ import * as path17 from "path";
1937
+ import * as os3 from "os";
1938
+ import * as crypto from "crypto";
1939
+ function getProjectTasks(projectName) {
1940
+ const config = loadMCPConfig();
1941
+ const projects = projectService.scan();
1942
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
1943
+ if (!project) {
1944
+ return [];
1945
+ }
1946
+ const permissions = getProjectPermissions(config, projectName, project.sourcePath || project.path);
1947
+ if (!permissions.tasks) {
1948
+ return [];
1949
+ }
1950
+ if (!project.tasksPath || !fs16.existsSync(project.tasksPath)) {
1951
+ return [];
1952
+ }
1953
+ const tasks = [];
1954
+ try {
1955
+ const taskDirs = fs16.readdirSync(project.tasksPath, { withFileTypes: true });
1956
+ for (const dir of taskDirs) {
1957
+ if (!dir.isDirectory()) continue;
1958
+ const metaPath = path17.join(project.tasksPath, dir.name, "meta.json");
1959
+ if (fs16.existsSync(metaPath)) {
1960
+ try {
1961
+ const meta = JSON.parse(fs16.readFileSync(metaPath, "utf-8"));
1962
+ tasks.push(meta);
1963
+ } catch (err) {
1964
+ logger.error(`[getProjectTasks] Failed to parse meta.json in ${dir.name}`, err);
1965
+ }
1966
+ }
1967
+ }
1968
+ } catch (err) {
1969
+ logger.error(`[getProjectTasks] Failed to read tasks directory ${project.tasksPath}`, err);
1970
+ }
1971
+ return tasks;
1972
+ }
1973
+ function getTask(projectName, taskSlug) {
1974
+ const config = loadMCPConfig();
1975
+ const projects = projectService.scan();
1976
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
1977
+ if (!project || !project.tasksPath) return null;
1978
+ const metaPath = path17.join(project.tasksPath, taskSlug, "meta.json");
1979
+ if (!fs16.existsSync(metaPath)) return null;
1980
+ try {
1981
+ return JSON.parse(fs16.readFileSync(metaPath, "utf-8"));
1982
+ } catch (err) {
1983
+ logger.error(`[getTask] Failed to parse meta.json for task ${taskSlug}`, err);
1984
+ return null;
1985
+ }
1986
+ }
1987
+ async function createTask(projectName, taskSlug, taskData) {
1988
+ const config = loadMCPConfig();
1989
+ const projects = projectService.scan();
1990
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
1991
+ if (!project || !project.tasksPath) {
1992
+ throw new Error(`Project '${projectName}' not found or not configured with a tasks path.`);
1993
+ }
1994
+ const taskDir = path17.join(project.tasksPath, taskSlug);
1995
+ if (fs16.existsSync(taskDir)) {
1996
+ throw new Error(`Task with slug '${taskSlug}' already exists.`);
1997
+ }
1998
+ fs16.mkdirSync(taskDir, { recursive: true });
1999
+ fs16.mkdirSync(path17.join(taskDir, "research"), { recursive: true });
2000
+ fs16.mkdirSync(path17.join(taskDir, "planning"), { recursive: true });
2001
+ fs16.mkdirSync(path17.join(taskDir, "execution"), { recursive: true });
2002
+ fs16.mkdirSync(path17.join(taskDir, "docs"), { recursive: true });
2003
+ const rrceHome = process.env.RRCE_HOME || path17.join(os3.homedir(), ".rrce-workflow");
2004
+ const templatePath = path17.join(rrceHome, "templates", "meta.template.json");
2005
+ let meta = {
2006
+ task_id: crypto.randomUUID(),
2007
+ task_slug: taskSlug,
2008
+ status: "draft",
2009
+ agents: {}
2010
+ };
2011
+ if (fs16.existsSync(templatePath)) {
2012
+ try {
2013
+ const template = JSON.parse(fs16.readFileSync(templatePath, "utf-8"));
2014
+ meta = { ...template, ...meta };
2015
+ } catch (e) {
2016
+ logger.error("Failed to load meta template", e);
2017
+ }
2018
+ }
2019
+ meta.created_at = (/* @__PURE__ */ new Date()).toISOString();
2020
+ meta.updated_at = meta.created_at;
2021
+ meta.workspace = {
2022
+ name: project.name,
2023
+ path: project.path || project.dataPath,
2024
+ hash: project.name
2025
+ };
2026
+ Object.assign(meta, taskData);
2027
+ const metaPath = path17.join(taskDir, "meta.json");
2028
+ fs16.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
2029
+ return meta;
2030
+ }
2031
+ async function updateTask(projectName, taskSlug, taskData) {
2032
+ const meta = getTask(projectName, taskSlug);
2033
+ if (!meta) throw new Error(`Task '${taskSlug}' not found.`);
2034
+ const updatedMeta = {
2035
+ ...meta,
2036
+ ...taskData,
2037
+ updated_at: (/* @__PURE__ */ new Date()).toISOString(),
2038
+ // Ensure nested objects are merged if they exist in taskData
2039
+ agents: taskData.agents ? { ...meta.agents, ...taskData.agents } : meta.agents,
2040
+ workspace: meta.workspace
2041
+ // Protect workspace metadata
2042
+ };
2043
+ const config = loadMCPConfig();
2044
+ const projects = projectService.scan();
2045
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
2046
+ if (!project || !project.tasksPath) return null;
2047
+ const metaPath = path17.join(project.tasksPath, taskSlug, "meta.json");
2048
+ fs16.writeFileSync(metaPath, JSON.stringify(updatedMeta, null, 2));
2049
+ return updatedMeta;
2050
+ }
2051
+ function deleteTask(projectName, taskSlug) {
2052
+ const config = loadMCPConfig();
2053
+ const projects = projectService.scan();
2054
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
2055
+ if (!project || !project.tasksPath) return false;
2056
+ const taskDir = path17.join(project.tasksPath, taskSlug);
2057
+ if (!fs16.existsSync(taskDir)) return false;
2058
+ if (fs16.rmSync) {
2059
+ fs16.rmSync(taskDir, { recursive: true, force: true });
2060
+ } else {
2061
+ fs16.rmdirSync(taskDir, { recursive: true });
2062
+ }
2063
+ return true;
2064
+ }
2065
+ var init_tasks = __esm({
2066
+ "src/mcp/resources/tasks.ts"() {
2067
+ "use strict";
2068
+ init_logger();
2069
+ init_config();
2070
+ init_detection_service();
2071
+ }
2072
+ });
2073
+
1649
2074
  // src/mcp/services/rag.ts
1650
- import * as fs13 from "fs";
1651
- import * as path15 from "path";
2075
+ import * as fs17 from "fs";
2076
+ import * as path18 from "path";
1652
2077
  var INDEX_VERSION, DEFAULT_MODEL, RAGService;
1653
2078
  var init_rag = __esm({
1654
2079
  "src/mcp/services/rag.ts"() {
@@ -1702,9 +2127,9 @@ var init_rag = __esm({
1702
2127
  */
1703
2128
  loadIndex() {
1704
2129
  if (this.index) return;
1705
- if (fs13.existsSync(this.indexPath)) {
2130
+ if (fs17.existsSync(this.indexPath)) {
1706
2131
  try {
1707
- const data = fs13.readFileSync(this.indexPath, "utf-8");
2132
+ const data = fs17.readFileSync(this.indexPath, "utf-8");
1708
2133
  this.index = JSON.parse(data);
1709
2134
  logger.info(`[RAG] Loaded index from ${this.indexPath} with ${this.index?.chunks.length} chunks.`);
1710
2135
  } catch (error) {
@@ -1730,11 +2155,11 @@ var init_rag = __esm({
1730
2155
  saveIndex() {
1731
2156
  if (!this.index) return;
1732
2157
  try {
1733
- const dir = path15.dirname(this.indexPath);
1734
- if (!fs13.existsSync(dir)) {
1735
- fs13.mkdirSync(dir, { recursive: true });
2158
+ const dir = path18.dirname(this.indexPath);
2159
+ if (!fs17.existsSync(dir)) {
2160
+ fs17.mkdirSync(dir, { recursive: true });
1736
2161
  }
1737
- fs13.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
2162
+ fs17.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
1738
2163
  logger.info(`[RAG] Saved index to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
1739
2164
  } catch (error) {
1740
2165
  logger.error(`[RAG] Failed to save index to ${this.indexPath}`, error);
@@ -1745,13 +2170,13 @@ var init_rag = __esm({
1745
2170
  */
1746
2171
  saveIndexAtomic() {
1747
2172
  if (!this.index) return;
1748
- const dir = path15.dirname(this.indexPath);
1749
- if (!fs13.existsSync(dir)) {
1750
- fs13.mkdirSync(dir, { recursive: true });
2173
+ const dir = path18.dirname(this.indexPath);
2174
+ if (!fs17.existsSync(dir)) {
2175
+ fs17.mkdirSync(dir, { recursive: true });
1751
2176
  }
1752
2177
  const tmpPath = `${this.indexPath}.tmp`;
1753
- fs13.writeFileSync(tmpPath, JSON.stringify(this.index, null, 2));
1754
- fs13.renameSync(tmpPath, this.indexPath);
2178
+ fs17.writeFileSync(tmpPath, JSON.stringify(this.index, null, 2));
2179
+ fs17.renameSync(tmpPath, this.indexPath);
1755
2180
  }
1756
2181
  /**
1757
2182
  * Save index only if enough time passed since last save
@@ -2284,10 +2709,10 @@ var init_context_extractor = __esm({
2284
2709
  });
2285
2710
 
2286
2711
  // src/mcp/services/dependency-graph.ts
2287
- import * as fs14 from "fs";
2288
- import * as path16 from "path";
2712
+ import * as fs18 from "fs";
2713
+ import * as path19 from "path";
2289
2714
  function parseImports(filePath, content) {
2290
- const ext = path16.extname(filePath).toLowerCase();
2715
+ const ext = path19.extname(filePath).toLowerCase();
2291
2716
  const language = getLanguageFromExtension(ext);
2292
2717
  const edges = [];
2293
2718
  const patterns = IMPORT_PATTERNS[language] || IMPORT_PATTERNS.javascript || [];
@@ -2317,20 +2742,20 @@ function parseImports(filePath, content) {
2317
2742
  return edges;
2318
2743
  }
2319
2744
  function resolveImport(fromFile, importPath, language) {
2320
- const fromDir = path16.dirname(fromFile);
2745
+ const fromDir = path19.dirname(fromFile);
2321
2746
  if (importPath.startsWith(".")) {
2322
- const candidates = generateCandidates(path16.resolve(fromDir, importPath), language);
2747
+ const candidates = generateCandidates(path19.resolve(fromDir, importPath), language);
2323
2748
  for (const candidate of candidates) {
2324
- if (fs14.existsSync(candidate)) {
2749
+ if (fs18.existsSync(candidate)) {
2325
2750
  return { path: candidate, isResolved: true };
2326
2751
  }
2327
2752
  }
2328
- return { path: path16.resolve(fromDir, importPath), isResolved: false };
2753
+ return { path: path19.resolve(fromDir, importPath), isResolved: false };
2329
2754
  }
2330
2755
  if (importPath.startsWith("/")) {
2331
2756
  const candidates = generateCandidates(importPath, language);
2332
2757
  for (const candidate of candidates) {
2333
- if (fs14.existsSync(candidate)) {
2758
+ if (fs18.existsSync(candidate)) {
2334
2759
  return { path: candidate, isResolved: true };
2335
2760
  }
2336
2761
  }
@@ -2340,7 +2765,7 @@ function resolveImport(fromFile, importPath, language) {
2340
2765
  }
2341
2766
  function generateCandidates(basePath, language) {
2342
2767
  const candidates = [];
2343
- if (path16.extname(basePath)) {
2768
+ if (path19.extname(basePath)) {
2344
2769
  candidates.push(basePath);
2345
2770
  }
2346
2771
  switch (language) {
@@ -2455,18 +2880,18 @@ async function scanProjectDependencies(projectRoot, options = {}) {
2455
2880
  const files = [];
2456
2881
  function scanDir(dir) {
2457
2882
  try {
2458
- const entries = fs14.readdirSync(dir, { withFileTypes: true });
2883
+ const entries = fs18.readdirSync(dir, { withFileTypes: true });
2459
2884
  for (const entry of entries) {
2460
- const fullPath = path16.join(dir, entry.name);
2885
+ const fullPath = path19.join(dir, entry.name);
2461
2886
  if (entry.isDirectory()) {
2462
2887
  if (!skipDirs.includes(entry.name) && !entry.name.startsWith(".")) {
2463
2888
  scanDir(fullPath);
2464
2889
  }
2465
2890
  } else if (entry.isFile()) {
2466
- const ext = path16.extname(entry.name).toLowerCase();
2891
+ const ext = path19.extname(entry.name).toLowerCase();
2467
2892
  if (extensions.includes(ext)) {
2468
2893
  try {
2469
- const content = fs14.readFileSync(fullPath, "utf-8");
2894
+ const content = fs18.readFileSync(fullPath, "utf-8");
2470
2895
  files.push({ path: fullPath, content });
2471
2896
  } catch {
2472
2897
  }
@@ -2715,222 +3140,57 @@ function getLanguageFromPath(filePath) {
2715
3140
  const langMap = {
2716
3141
  "ts": "typescript",
2717
3142
  "tsx": "typescript",
2718
- "js": "javascript",
2719
- "jsx": "javascript",
2720
- "mjs": "javascript",
2721
- "cjs": "javascript",
2722
- "py": "python",
2723
- "go": "go",
2724
- "rs": "rust",
2725
- "java": "java",
2726
- "kt": "kotlin",
2727
- "rb": "ruby",
2728
- "php": "php",
2729
- "swift": "swift",
2730
- "c": "c",
2731
- "cpp": "cpp",
2732
- "h": "c",
2733
- "hpp": "cpp",
2734
- "cs": "csharp"
2735
- };
2736
- return langMap[ext] ?? "unknown";
2737
- }
2738
- function searchSymbols(symbolResults, query, options = {}) {
2739
- const { type = "any", fuzzy = true, limit = 10, minScore = 0.3 } = options;
2740
- const matches = [];
2741
- for (const result of symbolResults) {
2742
- for (const symbol of result.symbols) {
2743
- if (type !== "any" && symbol.type !== type) continue;
2744
- const score = fuzzy ? fuzzyMatchScore(query, symbol.name) : symbol.name.toLowerCase().includes(query.toLowerCase()) ? 1 : 0;
2745
- if (score >= minScore) {
2746
- matches.push({
2747
- ...symbol,
2748
- file: result.filePath,
2749
- score
2750
- });
2751
- }
2752
- }
2753
- }
2754
- matches.sort((a, b) => {
2755
- if (b.score !== a.score) return b.score - a.score;
2756
- return a.name.length - b.name.length;
2757
- });
2758
- return matches.slice(0, limit);
2759
- }
2760
- var init_symbol_extractor = __esm({
2761
- "src/mcp/services/symbol-extractor.ts"() {
2762
- "use strict";
2763
- }
2764
- });
2765
-
2766
- // src/mcp/resources.ts
2767
- import * as fs15 from "fs";
2768
- import * as path17 from "path";
2769
- import * as os3 from "os";
2770
- import * as crypto from "crypto";
2771
- import ignore from "ignore";
2772
- function resolveProjectPaths(project, pathInput) {
2773
- const config = loadMCPConfig();
2774
- let workspaceRoot = pathInput;
2775
- let workspaceName = project;
2776
- if (!workspaceRoot && project) {
2777
- const projConfig = findProjectConfig(config, { name: project });
2778
- if (projConfig?.path) {
2779
- workspaceRoot = projConfig.path;
2780
- }
2781
- }
2782
- if (!workspaceName && workspaceRoot) {
2783
- const projConfig = findProjectConfig(config, { path: workspaceRoot });
2784
- workspaceName = projConfig?.name || getWorkspaceName(workspaceRoot);
2785
- }
2786
- if (!workspaceName) {
2787
- workspaceName = "unknown";
2788
- }
2789
- let rrceData = "";
2790
- let mode = "global";
2791
- let configFilePath = "";
2792
- if (workspaceRoot) {
2793
- configFilePath = getConfigPath(workspaceRoot);
2794
- const rrceHome = getEffectiveGlobalPath();
2795
- if (configFilePath.startsWith(rrceHome)) {
2796
- mode = "global";
2797
- } else {
2798
- mode = "workspace";
2799
- if (fs15.existsSync(configFilePath)) {
2800
- const content = fs15.readFileSync(configFilePath, "utf-8");
2801
- if (content.includes("mode: global")) mode = "global";
2802
- if (content.includes("mode: workspace")) mode = "workspace";
2803
- }
2804
- }
2805
- rrceData = resolveDataPath(mode, workspaceName, workspaceRoot);
2806
- } else {
2807
- rrceData = resolveDataPath("global", workspaceName, "");
2808
- }
2809
- return {
2810
- RRCE_HOME: getRRCEHome(),
2811
- RRCE_DATA: rrceData,
2812
- WORKSPACE_ROOT: workspaceRoot || null,
2813
- WORKSPACE_NAME: workspaceName,
2814
- storage_mode: mode,
2815
- config_path: configFilePath || null
2816
- };
2817
- }
2818
- function getExposedProjects() {
2819
- const config = loadMCPConfig();
2820
- const knownProjects = config.projects.filter((p) => !!p.path).map((p) => ({ name: p.name, path: p.path }));
2821
- const allProjects = projectService.scan({ knownProjects });
2822
- const activeProject = detectActiveProject(allProjects);
2823
- const potentialProjects = [...allProjects];
2824
- if (activeProject) {
2825
- let cfgContent = null;
2826
- if (fs15.existsSync(path17.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
2827
- cfgContent = fs15.readFileSync(path17.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
2828
- } else if (fs15.existsSync(path17.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
2829
- cfgContent = fs15.readFileSync(path17.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
2830
- }
2831
- if (cfgContent) {
2832
- if (cfgContent.includes("linked_projects:")) {
2833
- const lines = cfgContent.split("\n");
2834
- let inLinked = false;
2835
- for (const line of lines) {
2836
- const trimmed = line.trim();
2837
- if (trimmed.startsWith("linked_projects:")) {
2838
- inLinked = true;
2839
- continue;
2840
- }
2841
- if (inLinked) {
2842
- if (trimmed.startsWith("-") || trimmed.startsWith("linked_projects")) {
2843
- } else if (trimmed !== "" && !trimmed.startsWith("#")) {
2844
- inLinked = false;
2845
- }
2846
- if (inLinked && trimmed.startsWith("-")) {
2847
- const val = trimmed.replace(/^-\s*/, "").trim();
2848
- const [pName] = val.split(":");
2849
- if (!potentialProjects.some((p) => p.name === pName)) {
2850
- const found = allProjects.find((p) => p.name === pName);
2851
- if (found) {
2852
- potentialProjects.push(found);
2853
- }
2854
- }
2855
- }
2856
- }
2857
- }
2858
- }
2859
- }
2860
- }
2861
- return potentialProjects.filter((project) => isProjectExposed(config, project.name, project.sourcePath || project.path));
2862
- }
2863
- function getCodeIndexPath(project) {
2864
- const scanRoot = project.path || project.dataPath;
2865
- return path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
2866
- }
2867
- function detectActiveProject(knownProjects) {
2868
- let scanList = knownProjects;
2869
- if (!scanList) {
2870
- const config = loadMCPConfig();
2871
- const knownProjectsMap = config.projects.filter((p) => !!p.path).map((p) => ({ name: p.name, path: p.path }));
2872
- const all = projectService.scan({ knownProjects: knownProjectsMap });
2873
- scanList = all.filter((project) => isProjectExposed(config, project.name, project.sourcePath || project.path));
2874
- }
2875
- return findClosestProject(scanList);
2876
- }
2877
- function getProjectContext(projectName) {
2878
- const config = loadMCPConfig();
2879
- const projects = projectService.scan();
2880
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
2881
- if (!project) {
2882
- return null;
2883
- }
2884
- const permissions = getProjectPermissions(config, projectName, project.sourcePath || project.path);
2885
- if (!permissions.knowledge) {
2886
- return null;
2887
- }
2888
- if (!project.knowledgePath) {
2889
- return null;
2890
- }
2891
- const contextPath = path17.join(project.knowledgePath, "project-context.md");
2892
- if (!fs15.existsSync(contextPath)) {
2893
- return null;
2894
- }
2895
- return fs15.readFileSync(contextPath, "utf-8");
2896
- }
2897
- function getProjectTasks(projectName) {
2898
- const config = loadMCPConfig();
2899
- const projects = projectService.scan();
2900
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
2901
- if (!project) {
2902
- return [];
2903
- }
2904
- const permissions = getProjectPermissions(config, projectName, project.sourcePath || project.path);
2905
- if (!permissions.tasks) {
2906
- return [];
2907
- }
2908
- if (!project.tasksPath || !fs15.existsSync(project.tasksPath)) {
2909
- return [];
2910
- }
2911
- const tasks = [];
2912
- try {
2913
- const taskDirs = fs15.readdirSync(project.tasksPath, { withFileTypes: true });
2914
- for (const dir of taskDirs) {
2915
- if (!dir.isDirectory()) continue;
2916
- const metaPath = path17.join(project.tasksPath, dir.name, "meta.json");
2917
- if (fs15.existsSync(metaPath)) {
2918
- try {
2919
- const meta = JSON.parse(fs15.readFileSync(metaPath, "utf-8"));
2920
- tasks.push(meta);
2921
- } catch (err) {
2922
- logger.error(`[getProjectTasks] Failed to parse meta.json in ${dir.name}`, err);
2923
- }
3143
+ "js": "javascript",
3144
+ "jsx": "javascript",
3145
+ "mjs": "javascript",
3146
+ "cjs": "javascript",
3147
+ "py": "python",
3148
+ "go": "go",
3149
+ "rs": "rust",
3150
+ "java": "java",
3151
+ "kt": "kotlin",
3152
+ "rb": "ruby",
3153
+ "php": "php",
3154
+ "swift": "swift",
3155
+ "c": "c",
3156
+ "cpp": "cpp",
3157
+ "h": "c",
3158
+ "hpp": "cpp",
3159
+ "cs": "csharp"
3160
+ };
3161
+ return langMap[ext] ?? "unknown";
3162
+ }
3163
+ function searchSymbols(symbolResults, query, options = {}) {
3164
+ const { type = "any", fuzzy = true, limit = 10, minScore = 0.3 } = options;
3165
+ const matches = [];
3166
+ for (const result of symbolResults) {
3167
+ for (const symbol of result.symbols) {
3168
+ if (type !== "any" && symbol.type !== type) continue;
3169
+ const score = fuzzy ? fuzzyMatchScore(query, symbol.name) : symbol.name.toLowerCase().includes(query.toLowerCase()) ? 1 : 0;
3170
+ if (score >= minScore) {
3171
+ matches.push({
3172
+ ...symbol,
3173
+ file: result.filePath,
3174
+ score
3175
+ });
2924
3176
  }
2925
3177
  }
2926
- } catch (err) {
2927
- logger.error(`[getProjectTasks] Failed to read tasks directory ${project.tasksPath}`, err);
2928
3178
  }
2929
- return tasks;
2930
- }
2931
- function estimateTokens(text2) {
2932
- return Math.ceil(text2.length / 4);
3179
+ matches.sort((a, b) => {
3180
+ if (b.score !== a.score) return b.score - a.score;
3181
+ return a.name.length - b.name.length;
3182
+ });
3183
+ return matches.slice(0, limit);
2933
3184
  }
3185
+ var init_symbol_extractor = __esm({
3186
+ "src/mcp/services/symbol-extractor.ts"() {
3187
+ "use strict";
3188
+ }
3189
+ });
3190
+
3191
+ // src/mcp/resources/search.ts
3192
+ import * as fs19 from "fs";
3193
+ import * as path20 from "path";
2934
3194
  async function searchCode(query, projectFilter, limit = 10, options) {
2935
3195
  const config = loadMCPConfig();
2936
3196
  const projects = getExposedProjects();
@@ -2949,7 +3209,7 @@ async function searchCode(query, projectFilter, limit = 10, options) {
2949
3209
  }
2950
3210
  try {
2951
3211
  const codeIndexPath = getCodeIndexPath(project);
2952
- if (!fs15.existsSync(codeIndexPath)) {
3212
+ if (!fs19.existsSync(codeIndexPath)) {
2953
3213
  logger.debug(`[searchCode] Code index not found for project '${project.name}'`);
2954
3214
  continue;
2955
3215
  }
@@ -2959,7 +3219,7 @@ async function searchCode(query, projectFilter, limit = 10, options) {
2959
3219
  const codeChunk = r;
2960
3220
  results.push({
2961
3221
  project: project.name,
2962
- file: path17.relative(project.sourcePath || project.path || "", codeChunk.filePath),
3222
+ file: path20.relative(project.sourcePath || project.path || "", codeChunk.filePath),
2963
3223
  snippet: codeChunk.content,
2964
3224
  lineStart: codeChunk.lineStart ?? 1,
2965
3225
  lineEnd: codeChunk.lineEnd ?? 1,
@@ -3040,15 +3300,14 @@ async function searchKnowledge(query, projectFilter, options) {
3040
3300
  if (useRAG) {
3041
3301
  logger.info(`[RAG] Using semantic search for project '${project.name}'`);
3042
3302
  try {
3043
- const indexPath = path17.join(project.knowledgePath, "embeddings.json");
3303
+ const indexPath = path20.join(project.knowledgePath, "embeddings.json");
3044
3304
  const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
3045
3305
  const ragResults = await rag.search(query, 5);
3046
3306
  for (const r of ragResults) {
3047
3307
  results.push({
3048
3308
  project: project.name,
3049
- file: path17.relative(project.knowledgePath, r.filePath),
3309
+ file: path20.relative(project.knowledgePath, r.filePath),
3050
3310
  matches: [r.content],
3051
- // The chunk content is the match
3052
3311
  score: r.score,
3053
3312
  indexingInProgress: indexingInProgress2 || void 0,
3054
3313
  advisoryMessage: advisoryMessage2
@@ -3060,11 +3319,11 @@ async function searchKnowledge(query, projectFilter, options) {
3060
3319
  }
3061
3320
  }
3062
3321
  try {
3063
- const files = fs15.readdirSync(project.knowledgePath);
3322
+ const files = fs19.readdirSync(project.knowledgePath);
3064
3323
  for (const file of files) {
3065
3324
  if (!file.endsWith(".md")) continue;
3066
- const filePath = path17.join(project.knowledgePath, file);
3067
- const content = fs15.readFileSync(filePath, "utf-8");
3325
+ const filePath = path20.join(project.knowledgePath, file);
3326
+ const content = fs19.readFileSync(filePath, "utf-8");
3068
3327
  const lines = content.split("\n");
3069
3328
  const matches = [];
3070
3329
  for (const line of lines) {
@@ -3072,373 +3331,69 @@ async function searchKnowledge(query, projectFilter, options) {
3072
3331
  matches.push(line.trim());
3073
3332
  }
3074
3333
  }
3075
- if (matches.length > 0) {
3076
- results.push({
3077
- project: project.name,
3078
- file,
3079
- matches: matches.slice(0, 5),
3080
- // Limit to 5 matches per file
3081
- indexingInProgress: indexingInProgress2 || void 0,
3082
- advisoryMessage: advisoryMessage2
3083
- });
3084
- }
3085
- }
3086
- } catch (err) {
3087
- logger.error(`[searchKnowledge] Failed to read knowledge directory ${project.knowledgePath}`, err);
3088
- }
3089
- }
3090
- let filteredResults = results;
3091
- if (options?.min_score !== void 0 && options.min_score > 0) {
3092
- filteredResults = results.filter((r) => (r.score ?? 1) >= options.min_score);
3093
- }
3094
- filteredResults.sort((a, b) => (b.score ?? 1) - (a.score ?? 1));
3095
- let truncated = false;
3096
- let tokenCount = 0;
3097
- let budgetedResults = filteredResults;
3098
- if (options?.max_tokens !== void 0 && options.max_tokens > 0) {
3099
- budgetedResults = [];
3100
- for (const result of filteredResults) {
3101
- const resultTokens = estimateTokens(result.matches.join("\n"));
3102
- if (tokenCount + resultTokens > options.max_tokens) {
3103
- truncated = true;
3104
- break;
3105
- }
3106
- budgetedResults.push(result);
3107
- tokenCount += resultTokens;
3108
- }
3109
- } else {
3110
- tokenCount = filteredResults.reduce((sum, r) => sum + estimateTokens(r.matches.join("\n")), 0);
3111
- }
3112
- let indexAgeSeconds;
3113
- let lastIndexedAt;
3114
- let indexingInProgress;
3115
- let advisoryMessage;
3116
- if (projectFilter) {
3117
- const project = projects.find((p) => p.name === projectFilter);
3118
- if (project) {
3119
- indexingInProgress = indexingJobs.isRunning(project.name);
3120
- advisoryMessage = indexingInProgress ? "Indexing in progress; results may be stale/incomplete." : void 0;
3121
- const progress = indexingJobs.getProgress(project.name);
3122
- if (progress.completedAt) {
3123
- lastIndexedAt = new Date(progress.completedAt).toISOString();
3124
- indexAgeSeconds = Math.floor((Date.now() - progress.completedAt) / 1e3);
3125
- }
3126
- }
3127
- }
3128
- const cleanResults = budgetedResults.map(({ indexingInProgress: _, advisoryMessage: __, ...rest }) => rest);
3129
- return {
3130
- results: cleanResults,
3131
- token_count: tokenCount,
3132
- truncated,
3133
- index_age_seconds: indexAgeSeconds,
3134
- last_indexed_at: lastIndexedAt,
3135
- indexingInProgress,
3136
- advisoryMessage
3137
- };
3138
- }
3139
- function getScanContext(project, scanRoot) {
3140
- const gitignorePath = path17.join(scanRoot, ".gitignore");
3141
- const ig = fs15.existsSync(gitignorePath) ? ignore().add(fs15.readFileSync(gitignorePath, "utf-8")) : null;
3142
- const toPosixRelativePath = (absolutePath) => {
3143
- const rel = path17.relative(scanRoot, absolutePath);
3144
- return rel.split(path17.sep).join("/");
3145
- };
3146
- const isUnderGitDir = (absolutePath) => {
3147
- const rel = toPosixRelativePath(absolutePath);
3148
- return rel === ".git" || rel.startsWith(".git/");
3149
- };
3150
- const isIgnoredByGitignore = (absolutePath, isDir) => {
3151
- if (!ig) return false;
3152
- const rel = toPosixRelativePath(absolutePath);
3153
- return ig.ignores(isDir ? `${rel}/` : rel);
3154
- };
3155
- const shouldSkipEntryDir = (absolutePath) => {
3156
- const dirName = path17.basename(absolutePath);
3157
- if (dirName === ".git") return true;
3158
- if (SKIP_DIRS.includes(dirName)) return true;
3159
- if (isIgnoredByGitignore(absolutePath, true)) return true;
3160
- return false;
3161
- };
3162
- const shouldSkipEntryFile = (absolutePath) => {
3163
- if (isUnderGitDir(absolutePath)) return true;
3164
- if (isIgnoredByGitignore(absolutePath, false)) return true;
3165
- return false;
3166
- };
3167
- return { shouldSkipEntryDir, shouldSkipEntryFile };
3168
- }
3169
- async function indexKnowledge(projectName, force = false) {
3170
- const config = loadMCPConfig();
3171
- const projects = getExposedProjects();
3172
- const project = projects.find((p2) => p2.name === projectName || p2.path && p2.path === projectName);
3173
- if (!project) {
3174
- return {
3175
- state: "failed",
3176
- status: "failed",
3177
- success: false,
3178
- message: `Project '${projectName}' not found`,
3179
- filesIndexed: 0,
3180
- filesSkipped: 0,
3181
- progress: { itemsDone: 0 }
3182
- };
3183
- }
3184
- const projConfig = findProjectConfig(config, { name: project.name, path: project.sourcePath || project.path }) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
3185
- const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
3186
- if (!isEnabled) {
3187
- return {
3188
- state: "failed",
3189
- status: "failed",
3190
- success: false,
3191
- message: "Semantic Search is not enabled for this project",
3192
- filesIndexed: 0,
3193
- filesSkipped: 0,
3194
- progress: { itemsDone: 0 }
3195
- };
3196
- }
3197
- const scanRoot = project.sourcePath || project.path || project.dataPath;
3198
- if (!fs15.existsSync(scanRoot)) {
3199
- return {
3200
- state: "failed",
3201
- status: "failed",
3202
- success: false,
3203
- message: "Project root not found",
3204
- filesIndexed: 0,
3205
- filesSkipped: 0,
3206
- progress: { itemsDone: 0 }
3207
- };
3208
- }
3209
- const runIndexing = async () => {
3210
- const { shouldSkipEntryDir, shouldSkipEntryFile } = getScanContext(project, scanRoot);
3211
- const indexPath = path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
3212
- const codeIndexPath = path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
3213
- const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
3214
- const rag = new RAGService(indexPath, model);
3215
- const codeRag = new RAGService(codeIndexPath, model);
3216
- let indexed = 0;
3217
- let codeIndexed = 0;
3218
- let skipped = 0;
3219
- let itemsTotal = 0;
3220
- let itemsDone = 0;
3221
- const preCount = (dir) => {
3222
- const entries = fs15.readdirSync(dir, { withFileTypes: true });
3223
- for (const entry of entries) {
3224
- const fullPath = path17.join(dir, entry.name);
3225
- if (entry.isDirectory()) {
3226
- if (shouldSkipEntryDir(fullPath)) continue;
3227
- preCount(fullPath);
3228
- } else if (entry.isFile()) {
3229
- const ext = path17.extname(entry.name).toLowerCase();
3230
- if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
3231
- if (shouldSkipEntryFile(fullPath)) continue;
3232
- itemsTotal++;
3233
- }
3234
- }
3235
- };
3236
- preCount(scanRoot);
3237
- indexingJobs.update(project.name, { itemsTotal });
3238
- const cleanupIgnoredFiles = async () => {
3239
- const indexedFiles = [...rag.getIndexedFiles(), ...codeRag.getIndexedFiles()];
3240
- const unique = Array.from(new Set(indexedFiles));
3241
- for (const filePath of unique) {
3242
- if (!path17.isAbsolute(filePath)) continue;
3243
- const relFilePath = filePath.split(path17.sep).join("/");
3244
- const relScanRoot = scanRoot.split(path17.sep).join("/");
3245
- const isInScanRoot = relFilePath === relScanRoot || relFilePath.startsWith(`${relScanRoot}/`);
3246
- if (!isInScanRoot) continue;
3247
- if (shouldSkipEntryFile(filePath)) {
3248
- await rag.removeFile(filePath);
3249
- await codeRag.removeFile(filePath);
3250
- }
3251
- }
3252
- };
3253
- await cleanupIgnoredFiles();
3254
- const scanDir = async (dir) => {
3255
- const entries = fs15.readdirSync(dir, { withFileTypes: true });
3256
- for (const entry of entries) {
3257
- const fullPath = path17.join(dir, entry.name);
3258
- if (entry.isDirectory()) {
3259
- if (shouldSkipEntryDir(fullPath)) continue;
3260
- await scanDir(fullPath);
3261
- } else if (entry.isFile()) {
3262
- const ext = path17.extname(entry.name).toLowerCase();
3263
- if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
3264
- if (shouldSkipEntryFile(fullPath)) continue;
3265
- try {
3266
- indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
3267
- const stat = fs15.statSync(fullPath);
3268
- const mtime = force ? void 0 : stat.mtimeMs;
3269
- const content = fs15.readFileSync(fullPath, "utf-8");
3270
- const wasIndexed = await rag.indexFile(fullPath, content, mtime);
3271
- if (wasIndexed) {
3272
- indexed++;
3273
- } else {
3274
- skipped++;
3275
- }
3276
- if (CODE_EXTENSIONS.includes(ext)) {
3277
- if (!mtime || codeRag.needsReindex(fullPath, mtime)) {
3278
- const language = getLanguageFromExtension(ext);
3279
- const chunks = codeRag.chunkContentWithLines(content);
3280
- codeRag.clearFileChunks(fullPath);
3281
- for (const chunk of chunks) {
3282
- const context = extractContext(content, chunk.lineStart, language);
3283
- await codeRag.indexCodeChunk(fullPath, chunk, context, language, mtime);
3284
- }
3285
- codeRag.updateFileMetadata(fullPath, chunks.length, mtime ?? Date.now(), language);
3286
- codeIndexed++;
3287
- }
3288
- }
3289
- } catch (err) {
3290
- logger.error(`[indexKnowledge] Failed to index ${fullPath}`, err);
3291
- } finally {
3292
- itemsDone++;
3293
- indexingJobs.update(project.name, { itemsDone });
3294
- if (itemsDone % 10 === 0) {
3295
- await new Promise((resolve4) => setImmediate(resolve4));
3296
- }
3297
- }
3334
+ if (matches.length > 0) {
3335
+ results.push({
3336
+ project: project.name,
3337
+ file,
3338
+ matches: matches.slice(0, 5),
3339
+ // Limit to 5 matches per file
3340
+ indexingInProgress: indexingInProgress2 || void 0,
3341
+ advisoryMessage: advisoryMessage2
3342
+ });
3298
3343
  }
3299
3344
  }
3300
- };
3301
- await scanDir(scanRoot);
3302
- rag.markFullIndex();
3303
- codeRag.markFullIndex();
3304
- const stats = rag.getStats();
3305
- const codeStats = codeRag.getStats();
3306
- const message = `Indexed ${indexed} files (${codeIndexed} code files), skipped ${skipped} unchanged. Knowledge: ${stats.totalChunks} chunks. Code: ${codeStats.totalChunks} chunks.`;
3307
- logger.info(`[RAG] ${project.name}: ${message}`);
3308
- indexingJobs.update(project.name, { currentItem: void 0 });
3309
- };
3310
- const startResult = indexingJobs.startOrStatus(project.name, runIndexing);
3311
- const p = startResult.progress;
3312
- return {
3313
- state: startResult.state,
3314
- status: startResult.status,
3315
- success: startResult.status === "started" || startResult.status === "already_running",
3316
- message: startResult.status === "started" ? `Indexing started in background for '${project.name}'.` : `Indexing already running for '${project.name}'.`,
3317
- filesIndexed: 0,
3318
- filesSkipped: 0,
3319
- progress: {
3320
- itemsDone: p.itemsDone,
3321
- itemsTotal: p.itemsTotal,
3322
- currentItem: p.currentItem,
3323
- startedAt: p.startedAt,
3324
- completedAt: p.completedAt,
3325
- lastError: p.lastError
3345
+ } catch (err) {
3346
+ logger.error(`[searchKnowledge] Failed to read knowledge directory ${project.knowledgePath}`, err);
3326
3347
  }
3327
- };
3328
- }
3329
- function getContextPreamble() {
3330
- const activeProject = detectActiveProject();
3331
- if (!activeProject) {
3332
- return `## System Context
3333
- No active project detected. Run \`rrce-workflow mcp configure\` to expose projects.
3334
- ---
3335
- `;
3336
- }
3337
- const rrceHome = process.env.RRCE_HOME || path17.join(os3.homedir(), ".rrce-workflow");
3338
- const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
3339
- const rrceData = activeProject.dataPath;
3340
- return `## System Context
3341
- | Key | Value |
3342
- |-----|-------|
3343
- | WORKSPACE_ROOT | \`${workspaceRoot}\` |
3344
- | WORKSPACE_NAME | \`${activeProject.name}\` |
3345
- | RRCE_DATA | \`${rrceData}\` |
3346
- | RRCE_HOME | \`${rrceHome}\` |
3347
-
3348
- ---
3349
- `;
3350
- }
3351
- function getTask(projectName, taskSlug) {
3352
- const config = loadMCPConfig();
3353
- const projects = projectService.scan();
3354
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
3355
- if (!project || !project.tasksPath) return null;
3356
- const metaPath = path17.join(project.tasksPath, taskSlug, "meta.json");
3357
- if (!fs15.existsSync(metaPath)) return null;
3358
- try {
3359
- return JSON.parse(fs15.readFileSync(metaPath, "utf-8"));
3360
- } catch (err) {
3361
- logger.error(`[getTask] Failed to parse meta.json for task ${taskSlug}`, err);
3362
- return null;
3363
3348
  }
3364
- }
3365
- async function createTask(projectName, taskSlug, taskData) {
3366
- const config = loadMCPConfig();
3367
- const projects = projectService.scan();
3368
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
3369
- if (!project || !project.tasksPath) {
3370
- throw new Error(`Project '${projectName}' not found or not configured with a tasks path.`);
3349
+ let filteredResults = results;
3350
+ if (options?.min_score !== void 0 && options.min_score > 0) {
3351
+ filteredResults = results.filter((r) => (r.score ?? 1) >= options.min_score);
3371
3352
  }
3372
- const taskDir = path17.join(project.tasksPath, taskSlug);
3373
- if (fs15.existsSync(taskDir)) {
3374
- throw new Error(`Task with slug '${taskSlug}' already exists.`);
3353
+ filteredResults.sort((a, b) => (b.score ?? 1) - (a.score ?? 1));
3354
+ let truncated = false;
3355
+ let tokenCount = 0;
3356
+ let budgetedResults = filteredResults;
3357
+ if (options?.max_tokens !== void 0 && options.max_tokens > 0) {
3358
+ budgetedResults = [];
3359
+ for (const result of filteredResults) {
3360
+ const resultTokens = estimateTokens(result.matches.join("\n"));
3361
+ if (tokenCount + resultTokens > options.max_tokens) {
3362
+ truncated = true;
3363
+ break;
3364
+ }
3365
+ budgetedResults.push(result);
3366
+ tokenCount += resultTokens;
3367
+ }
3368
+ } else {
3369
+ tokenCount = filteredResults.reduce((sum, r) => sum + estimateTokens(r.matches.join("\n")), 0);
3375
3370
  }
3376
- fs15.mkdirSync(taskDir, { recursive: true });
3377
- fs15.mkdirSync(path17.join(taskDir, "research"), { recursive: true });
3378
- fs15.mkdirSync(path17.join(taskDir, "planning"), { recursive: true });
3379
- fs15.mkdirSync(path17.join(taskDir, "execution"), { recursive: true });
3380
- fs15.mkdirSync(path17.join(taskDir, "docs"), { recursive: true });
3381
- const rrceHome = process.env.RRCE_HOME || path17.join(os3.homedir(), ".rrce-workflow");
3382
- const templatePath = path17.join(rrceHome, "templates", "meta.template.json");
3383
- let meta = {
3384
- task_id: crypto.randomUUID(),
3385
- task_slug: taskSlug,
3386
- status: "draft",
3387
- agents: {}
3388
- };
3389
- if (fs15.existsSync(templatePath)) {
3390
- try {
3391
- const template = JSON.parse(fs15.readFileSync(templatePath, "utf-8"));
3392
- meta = { ...template, ...meta };
3393
- } catch (e) {
3394
- logger.error("Failed to load meta template", e);
3371
+ let indexAgeSeconds;
3372
+ let lastIndexedAt;
3373
+ let indexingInProgress;
3374
+ let advisoryMessage;
3375
+ if (projectFilter) {
3376
+ const project = projects.find((p) => p.name === projectFilter);
3377
+ if (project) {
3378
+ indexingInProgress = indexingJobs.isRunning(project.name);
3379
+ advisoryMessage = indexingInProgress ? "Indexing in progress; results may be stale/incomplete." : void 0;
3380
+ const progress = indexingJobs.getProgress(project.name);
3381
+ if (progress.completedAt) {
3382
+ lastIndexedAt = new Date(progress.completedAt).toISOString();
3383
+ indexAgeSeconds = Math.floor((Date.now() - progress.completedAt) / 1e3);
3384
+ }
3395
3385
  }
3396
3386
  }
3397
- meta.created_at = (/* @__PURE__ */ new Date()).toISOString();
3398
- meta.updated_at = meta.created_at;
3399
- meta.workspace = {
3400
- name: project.name,
3401
- path: project.path || project.dataPath,
3402
- hash: project.name
3403
- };
3404
- Object.assign(meta, taskData);
3405
- const metaPath = path17.join(taskDir, "meta.json");
3406
- fs15.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
3407
- return meta;
3408
- }
3409
- async function updateTask(projectName, taskSlug, taskData) {
3410
- const meta = getTask(projectName, taskSlug);
3411
- if (!meta) throw new Error(`Task '${taskSlug}' not found.`);
3412
- const updatedMeta = {
3413
- ...meta,
3414
- ...taskData,
3415
- updated_at: (/* @__PURE__ */ new Date()).toISOString(),
3416
- // Ensure nested objects are merged if they exist in taskData
3417
- agents: taskData.agents ? { ...meta.agents, ...taskData.agents } : meta.agents,
3418
- workspace: meta.workspace
3419
- // Protect workspace metadata
3387
+ const cleanResults = budgetedResults.map(({ indexingInProgress: _, advisoryMessage: __, ...rest }) => rest);
3388
+ return {
3389
+ results: cleanResults,
3390
+ token_count: tokenCount,
3391
+ truncated,
3392
+ index_age_seconds: indexAgeSeconds,
3393
+ last_indexed_at: lastIndexedAt,
3394
+ indexingInProgress,
3395
+ advisoryMessage
3420
3396
  };
3421
- const config = loadMCPConfig();
3422
- const projects = projectService.scan();
3423
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
3424
- if (!project || !project.tasksPath) return null;
3425
- const metaPath = path17.join(project.tasksPath, taskSlug, "meta.json");
3426
- fs15.writeFileSync(metaPath, JSON.stringify(updatedMeta, null, 2));
3427
- return updatedMeta;
3428
- }
3429
- function deleteTask(projectName, taskSlug) {
3430
- const config = loadMCPConfig();
3431
- const projects = projectService.scan();
3432
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
3433
- if (!project || !project.tasksPath) return false;
3434
- const taskDir = path17.join(project.tasksPath, taskSlug);
3435
- if (!fs15.existsSync(taskDir)) return false;
3436
- if (fs15.rmSync) {
3437
- fs15.rmSync(taskDir, { recursive: true, force: true });
3438
- } else {
3439
- fs15.rmdirSync(taskDir, { recursive: true });
3440
- }
3441
- return true;
3442
3397
  }
3443
3398
  async function findRelatedFiles2(filePath, projectName, options = {}) {
3444
3399
  const config = loadMCPConfig();
@@ -3455,10 +3410,10 @@ async function findRelatedFiles2(filePath, projectName, options = {}) {
3455
3410
  }
3456
3411
  const projectRoot = project.sourcePath || project.path || "";
3457
3412
  let absoluteFilePath = filePath;
3458
- if (!path17.isAbsolute(filePath)) {
3459
- absoluteFilePath = path17.resolve(projectRoot, filePath);
3413
+ if (!path20.isAbsolute(filePath)) {
3414
+ absoluteFilePath = path20.resolve(projectRoot, filePath);
3460
3415
  }
3461
- if (!fs15.existsSync(absoluteFilePath)) {
3416
+ if (!fs19.existsSync(absoluteFilePath)) {
3462
3417
  return {
3463
3418
  success: false,
3464
3419
  file: filePath,
@@ -3475,13 +3430,13 @@ async function findRelatedFiles2(filePath, projectName, options = {}) {
3475
3430
  depth: options.depth ?? 1
3476
3431
  });
3477
3432
  const relationships = related.map((r) => ({
3478
- file: path17.relative(projectRoot, r.file),
3433
+ file: path20.relative(projectRoot, r.file),
3479
3434
  relationship: r.relationship,
3480
3435
  importPath: r.importPath
3481
3436
  }));
3482
3437
  return {
3483
3438
  success: true,
3484
- file: path17.relative(projectRoot, absoluteFilePath),
3439
+ file: path20.relative(projectRoot, absoluteFilePath),
3485
3440
  project: projectName,
3486
3441
  relationships
3487
3442
  };
@@ -3509,7 +3464,7 @@ async function searchSymbols2(name, projectName, options = {}) {
3509
3464
  };
3510
3465
  }
3511
3466
  const projectRoot = project.sourcePath || project.path || "";
3512
- if (!fs15.existsSync(projectRoot)) {
3467
+ if (!fs19.existsSync(projectRoot)) {
3513
3468
  return {
3514
3469
  success: false,
3515
3470
  project: projectName,
@@ -3520,14 +3475,14 @@ async function searchSymbols2(name, projectName, options = {}) {
3520
3475
  try {
3521
3476
  const codeFiles = [];
3522
3477
  const scanDir = (dir) => {
3523
- const entries = fs15.readdirSync(dir, { withFileTypes: true });
3478
+ const entries = fs19.readdirSync(dir, { withFileTypes: true });
3524
3479
  for (const entry of entries) {
3525
- const fullPath = path17.join(dir, entry.name);
3480
+ const fullPath = path20.join(dir, entry.name);
3526
3481
  if (entry.isDirectory()) {
3527
3482
  if (SKIP_DIRS.includes(entry.name)) continue;
3528
3483
  scanDir(fullPath);
3529
3484
  } else if (entry.isFile()) {
3530
- const ext = path17.extname(entry.name).toLowerCase();
3485
+ const ext = path20.extname(entry.name).toLowerCase();
3531
3486
  if (CODE_EXTENSIONS.includes(ext)) {
3532
3487
  codeFiles.push(fullPath);
3533
3488
  }
@@ -3538,7 +3493,7 @@ async function searchSymbols2(name, projectName, options = {}) {
3538
3493
  const symbolResults = [];
3539
3494
  for (const file of codeFiles.slice(0, 500)) {
3540
3495
  try {
3541
- const content = fs15.readFileSync(file, "utf-8");
3496
+ const content = fs19.readFileSync(file, "utf-8");
3542
3497
  const result = extractSymbols(content, file);
3543
3498
  symbolResults.push(result);
3544
3499
  } catch (e) {
@@ -3553,7 +3508,7 @@ async function searchSymbols2(name, projectName, options = {}) {
3553
3508
  const results = matches.map((m) => ({
3554
3509
  name: m.name,
3555
3510
  type: m.type,
3556
- file: path17.relative(projectRoot, m.file),
3511
+ file: path20.relative(projectRoot, m.file),
3557
3512
  line: m.line,
3558
3513
  signature: m.signature,
3559
3514
  exported: m.exported,
@@ -3586,24 +3541,24 @@ async function getFileSummary(filePath, projectName) {
3586
3541
  }
3587
3542
  const projectRoot = project.sourcePath || project.path || "";
3588
3543
  let absolutePath = filePath;
3589
- if (!path17.isAbsolute(filePath)) {
3590
- absolutePath = path17.resolve(projectRoot, filePath);
3544
+ if (!path20.isAbsolute(filePath)) {
3545
+ absolutePath = path20.resolve(projectRoot, filePath);
3591
3546
  }
3592
- if (!fs15.existsSync(absolutePath)) {
3547
+ if (!fs19.existsSync(absolutePath)) {
3593
3548
  return {
3594
3549
  success: false,
3595
3550
  message: `File not found: ${filePath}`
3596
3551
  };
3597
3552
  }
3598
3553
  try {
3599
- const stat = fs15.statSync(absolutePath);
3600
- const content = fs15.readFileSync(absolutePath, "utf-8");
3554
+ const stat = fs19.statSync(absolutePath);
3555
+ const content = fs19.readFileSync(absolutePath, "utf-8");
3601
3556
  const lines = content.split("\n");
3602
3557
  const symbolResult = extractSymbols(content, absolutePath);
3603
3558
  return {
3604
3559
  success: true,
3605
3560
  summary: {
3606
- path: path17.relative(projectRoot, absolutePath),
3561
+ path: path20.relative(projectRoot, absolutePath),
3607
3562
  language: symbolResult.language,
3608
3563
  lines: lines.length,
3609
3564
  size_bytes: stat.size,
@@ -3617,13 +3572,239 @@ async function getFileSummary(filePath, projectName) {
3617
3572
  }))
3618
3573
  }
3619
3574
  };
3620
- } catch (e) {
3621
- logger.error(`[getFileSummary] Error reading ${filePath}`, e);
3622
- return {
3623
- success: false,
3624
- message: `Error reading file: ${e instanceof Error ? e.message : String(e)}`
3575
+ } catch (e) {
3576
+ logger.error(`[getFileSummary] Error reading ${filePath}`, e);
3577
+ return {
3578
+ success: false,
3579
+ message: `Error reading file: ${e instanceof Error ? e.message : String(e)}`
3580
+ };
3581
+ }
3582
+ }
3583
+ var init_search = __esm({
3584
+ "src/mcp/resources/search.ts"() {
3585
+ "use strict";
3586
+ init_logger();
3587
+ init_config();
3588
+ init_config_utils();
3589
+ init_detection_service();
3590
+ init_rag();
3591
+ init_indexing_jobs();
3592
+ init_dependency_graph();
3593
+ init_symbol_extractor();
3594
+ init_projects();
3595
+ init_utils2();
3596
+ init_constants();
3597
+ }
3598
+ });
3599
+
3600
+ // src/mcp/resources/indexing.ts
3601
+ import * as fs20 from "fs";
3602
+ import * as path21 from "path";
3603
+ async function indexKnowledge(projectName, force = false) {
3604
+ const config = loadMCPConfig();
3605
+ const projects = getExposedProjects();
3606
+ const project = projects.find((p2) => p2.name === projectName || p2.path && p2.path === projectName);
3607
+ if (!project) {
3608
+ return {
3609
+ state: "failed",
3610
+ status: "failed",
3611
+ success: false,
3612
+ message: `Project '${projectName}' not found`,
3613
+ filesIndexed: 0,
3614
+ filesSkipped: 0,
3615
+ progress: { itemsDone: 0 }
3616
+ };
3617
+ }
3618
+ const projConfig = findProjectConfig(config, { name: project.name, path: project.sourcePath || project.path }) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
3619
+ const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
3620
+ if (!isEnabled) {
3621
+ return {
3622
+ state: "failed",
3623
+ status: "failed",
3624
+ success: false,
3625
+ message: "Semantic Search is not enabled for this project",
3626
+ filesIndexed: 0,
3627
+ filesSkipped: 0,
3628
+ progress: { itemsDone: 0 }
3629
+ };
3630
+ }
3631
+ const scanRoot = project.sourcePath || project.path || project.dataPath;
3632
+ if (!fs20.existsSync(scanRoot)) {
3633
+ return {
3634
+ state: "failed",
3635
+ status: "failed",
3636
+ success: false,
3637
+ message: "Project root not found",
3638
+ filesIndexed: 0,
3639
+ filesSkipped: 0,
3640
+ progress: { itemsDone: 0 }
3641
+ };
3642
+ }
3643
+ const runIndexing = async () => {
3644
+ const { shouldSkipEntryDir, shouldSkipEntryFile } = getScanContext(project, scanRoot);
3645
+ const indexPath = path21.join(project.knowledgePath || path21.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
3646
+ const codeIndexPath = path21.join(project.knowledgePath || path21.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
3647
+ const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
3648
+ const rag = new RAGService(indexPath, model);
3649
+ const codeRag = new RAGService(codeIndexPath, model);
3650
+ let indexed = 0;
3651
+ let codeIndexed = 0;
3652
+ let skipped = 0;
3653
+ let itemsTotal = 0;
3654
+ let itemsDone = 0;
3655
+ const preCount = (dir) => {
3656
+ const entries = fs20.readdirSync(dir, { withFileTypes: true });
3657
+ for (const entry of entries) {
3658
+ const fullPath = path21.join(dir, entry.name);
3659
+ if (entry.isDirectory()) {
3660
+ if (shouldSkipEntryDir(fullPath)) continue;
3661
+ preCount(fullPath);
3662
+ } else if (entry.isFile()) {
3663
+ const ext = path21.extname(entry.name).toLowerCase();
3664
+ if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
3665
+ if (shouldSkipEntryFile(fullPath)) continue;
3666
+ itemsTotal++;
3667
+ }
3668
+ }
3669
+ };
3670
+ preCount(scanRoot);
3671
+ indexingJobs.update(project.name, { itemsTotal });
3672
+ const cleanupIgnoredFiles = async () => {
3673
+ const indexedFiles = [...rag.getIndexedFiles(), ...codeRag.getIndexedFiles()];
3674
+ const unique = Array.from(new Set(indexedFiles));
3675
+ for (const filePath of unique) {
3676
+ if (!path21.isAbsolute(filePath)) continue;
3677
+ const relFilePath = filePath.split(path21.sep).join("/");
3678
+ const relScanRoot = scanRoot.split(path21.sep).join("/");
3679
+ const isInScanRoot = relFilePath === relScanRoot || relFilePath.startsWith(`${relScanRoot}/`);
3680
+ if (!isInScanRoot) continue;
3681
+ if (shouldSkipEntryFile(filePath)) {
3682
+ await rag.removeFile(filePath);
3683
+ await codeRag.removeFile(filePath);
3684
+ }
3685
+ }
3686
+ };
3687
+ await cleanupIgnoredFiles();
3688
+ const scanDir = async (dir) => {
3689
+ const entries = fs20.readdirSync(dir, { withFileTypes: true });
3690
+ for (const entry of entries) {
3691
+ const fullPath = path21.join(dir, entry.name);
3692
+ if (entry.isDirectory()) {
3693
+ if (shouldSkipEntryDir(fullPath)) continue;
3694
+ await scanDir(fullPath);
3695
+ } else if (entry.isFile()) {
3696
+ const ext = path21.extname(entry.name).toLowerCase();
3697
+ if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
3698
+ if (shouldSkipEntryFile(fullPath)) continue;
3699
+ try {
3700
+ indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
3701
+ const stat = fs20.statSync(fullPath);
3702
+ const mtime = force ? void 0 : stat.mtimeMs;
3703
+ const content = fs20.readFileSync(fullPath, "utf-8");
3704
+ const wasIndexed = await rag.indexFile(fullPath, content, mtime);
3705
+ if (wasIndexed) {
3706
+ indexed++;
3707
+ } else {
3708
+ skipped++;
3709
+ }
3710
+ if (CODE_EXTENSIONS.includes(ext)) {
3711
+ if (!mtime || codeRag.needsReindex(fullPath, mtime)) {
3712
+ const language = getLanguageFromExtension(ext);
3713
+ const chunks = codeRag.chunkContentWithLines(content);
3714
+ codeRag.clearFileChunks(fullPath);
3715
+ for (const chunk of chunks) {
3716
+ const context = extractContext(content, chunk.lineStart, language);
3717
+ await codeRag.indexCodeChunk(fullPath, chunk, context, language, mtime);
3718
+ }
3719
+ codeRag.updateFileMetadata(fullPath, chunks.length, mtime ?? Date.now(), language);
3720
+ codeIndexed++;
3721
+ }
3722
+ }
3723
+ } catch (err) {
3724
+ logger.error(`[indexKnowledge] Failed to index ${fullPath}`, err);
3725
+ } finally {
3726
+ itemsDone++;
3727
+ indexingJobs.update(project.name, { itemsDone });
3728
+ if (itemsDone % 10 === 0) {
3729
+ await new Promise((resolve4) => setImmediate(resolve4));
3730
+ }
3731
+ }
3732
+ }
3733
+ }
3625
3734
  };
3735
+ await scanDir(scanRoot);
3736
+ rag.markFullIndex();
3737
+ codeRag.markFullIndex();
3738
+ const stats = rag.getStats();
3739
+ const codeStats = codeRag.getStats();
3740
+ const message = `Indexed ${indexed} files (${codeIndexed} code files), skipped ${skipped} unchanged. Knowledge: ${stats.totalChunks} chunks. Code: ${codeStats.totalChunks} chunks.`;
3741
+ logger.info(`[RAG] ${project.name}: ${message}`);
3742
+ indexingJobs.update(project.name, { currentItem: void 0 });
3743
+ };
3744
+ const startResult = indexingJobs.startOrStatus(project.name, runIndexing);
3745
+ const p = startResult.progress;
3746
+ return {
3747
+ state: startResult.state,
3748
+ status: startResult.status,
3749
+ success: startResult.status === "started" || startResult.status === "already_running",
3750
+ message: startResult.status === "started" ? `Indexing started in background for '${project.name}'.` : `Indexing already running for '${project.name}'.`,
3751
+ filesIndexed: 0,
3752
+ filesSkipped: 0,
3753
+ progress: {
3754
+ itemsDone: p.itemsDone,
3755
+ itemsTotal: p.itemsTotal,
3756
+ currentItem: p.currentItem,
3757
+ startedAt: p.startedAt,
3758
+ completedAt: p.completedAt,
3759
+ lastError: p.lastError
3760
+ }
3761
+ };
3762
+ }
3763
+ var init_indexing = __esm({
3764
+ "src/mcp/resources/indexing.ts"() {
3765
+ "use strict";
3766
+ init_logger();
3767
+ init_config();
3768
+ init_config_utils();
3769
+ init_rag();
3770
+ init_indexing_jobs();
3771
+ init_context_extractor();
3772
+ init_projects();
3773
+ init_utils2();
3774
+ init_constants();
3775
+ }
3776
+ });
3777
+
3778
+ // src/mcp/resources/context.ts
3779
+ import * as path22 from "path";
3780
+ import * as os4 from "os";
3781
+ function getContextPreamble() {
3782
+ const activeProject = detectActiveProject();
3783
+ if (!activeProject) {
3784
+ return `## System Context
3785
+ No active project detected.
3786
+
3787
+ **To resolve paths manually:**
3788
+ - Call \`rrce_resolve_path(project: "your-project-name")\`
3789
+ - Or call \`rrce_list_projects()\` to see available projects
3790
+
3791
+ If the above tools fail, ask the user for clarification.
3792
+ ---
3793
+ `;
3626
3794
  }
3795
+ const rrceHome = process.env.RRCE_HOME || path22.join(os4.homedir(), ".rrce-workflow");
3796
+ const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
3797
+ const rrceData = activeProject.dataPath;
3798
+ return `## System Context
3799
+ | Key | Value |
3800
+ |-----|-------|
3801
+ | WORKSPACE_ROOT | \`${workspaceRoot}\` |
3802
+ | WORKSPACE_NAME | \`${activeProject.name}\` |
3803
+ | RRCE_DATA | \`${rrceData}\` |
3804
+ | RRCE_HOME | \`${rrceHome}\` |
3805
+
3806
+ ---
3807
+ `;
3627
3808
  }
3628
3809
  async function getContextBundle(query, projectName, options = {}) {
3629
3810
  const maxTokens = options.max_tokens ?? 4e3;
@@ -3768,6 +3949,18 @@ async function prefetchTaskContext(projectName, taskSlug, options = {}) {
3768
3949
  truncated: bundle.truncated
3769
3950
  };
3770
3951
  }
3952
+ var init_context = __esm({
3953
+ "src/mcp/resources/context.ts"() {
3954
+ "use strict";
3955
+ init_config_utils();
3956
+ init_projects();
3957
+ init_search();
3958
+ init_tasks();
3959
+ init_utils2();
3960
+ }
3961
+ });
3962
+
3963
+ // src/mcp/resources/validation.ts
3771
3964
  function searchTasks(projectName, options = {}) {
3772
3965
  const allTasks = getProjectTasks(projectName);
3773
3966
  const limit = options.limit ?? 20;
@@ -3886,6 +4079,16 @@ function validatePhase(projectName, taskSlug, phase) {
3886
4079
  suggestions
3887
4080
  };
3888
4081
  }
4082
+ var init_validation = __esm({
4083
+ "src/mcp/resources/validation.ts"() {
4084
+ "use strict";
4085
+ init_tasks();
4086
+ }
4087
+ });
4088
+
4089
+ // src/mcp/resources/sessions.ts
4090
+ import * as fs21 from "fs";
4091
+ import * as path23 from "path";
3889
4092
  function startSession(projectName, taskSlug, agent, phase) {
3890
4093
  const config = loadMCPConfig();
3891
4094
  const projects = projectService.scan();
@@ -3893,8 +4096,8 @@ function startSession(projectName, taskSlug, agent, phase) {
3893
4096
  if (!project || !project.tasksPath) {
3894
4097
  return { success: false, message: `Project '${projectName}' not found or not exposed.` };
3895
4098
  }
3896
- const taskDir = path17.join(project.tasksPath, taskSlug);
3897
- if (!fs15.existsSync(taskDir)) {
4099
+ const taskDir = path23.join(project.tasksPath, taskSlug);
4100
+ if (!fs21.existsSync(taskDir)) {
3898
4101
  return { success: false, message: `Task '${taskSlug}' not found.` };
3899
4102
  }
3900
4103
  const session = {
@@ -3904,8 +4107,8 @@ function startSession(projectName, taskSlug, agent, phase) {
3904
4107
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
3905
4108
  heartbeat: (/* @__PURE__ */ new Date()).toISOString()
3906
4109
  };
3907
- const sessionPath = path17.join(taskDir, "session.json");
3908
- fs15.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
4110
+ const sessionPath = path23.join(taskDir, "session.json");
4111
+ fs21.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
3909
4112
  return { success: true, message: `Session started for ${agent} agent on task '${taskSlug}' (phase: ${phase})` };
3910
4113
  }
3911
4114
  function endSession(projectName, taskSlug) {
@@ -3915,11 +4118,11 @@ function endSession(projectName, taskSlug) {
3915
4118
  if (!project || !project.tasksPath) {
3916
4119
  return { success: false, message: `Project '${projectName}' not found or not exposed.` };
3917
4120
  }
3918
- const sessionPath = path17.join(project.tasksPath, taskSlug, "session.json");
3919
- if (!fs15.existsSync(sessionPath)) {
4121
+ const sessionPath = path23.join(project.tasksPath, taskSlug, "session.json");
4122
+ if (!fs21.existsSync(sessionPath)) {
3920
4123
  return { success: true, message: `No active session for task '${taskSlug}'.` };
3921
4124
  }
3922
- fs15.unlinkSync(sessionPath);
4125
+ fs21.unlinkSync(sessionPath);
3923
4126
  return { success: true, message: `Session ended for task '${taskSlug}'.` };
3924
4127
  }
3925
4128
  function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
@@ -3929,9 +4132,9 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
3929
4132
  if (!project || !project.tasksPath) {
3930
4133
  return { success: false, message: `Project '${projectName}' not found or not exposed.` };
3931
4134
  }
3932
- const taskDir = path17.join(project.tasksPath, taskSlug);
3933
- if (!fs15.existsSync(taskDir)) {
3934
- fs15.mkdirSync(taskDir, { recursive: true });
4135
+ const taskDir = path23.join(project.tasksPath, taskSlug);
4136
+ if (!fs21.existsSync(taskDir)) {
4137
+ fs21.mkdirSync(taskDir, { recursive: true });
3935
4138
  }
3936
4139
  const todos = {
3937
4140
  phase,
@@ -3939,91 +4142,41 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
3939
4142
  items,
3940
4143
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
3941
4144
  };
3942
- const todosPath = path17.join(taskDir, "agent-todos.json");
3943
- fs15.writeFileSync(todosPath, JSON.stringify(todos, null, 2));
4145
+ const todosPath = path23.join(taskDir, "agent-todos.json");
4146
+ fs21.writeFileSync(todosPath, JSON.stringify(todos, null, 2));
3944
4147
  return { success: true, message: `Updated ${items.length} todo items for task '${taskSlug}'.`, count: items.length };
3945
4148
  }
3946
- var INDEXABLE_EXTENSIONS, CODE_EXTENSIONS, SKIP_DIRS;
3947
- var init_resources = __esm({
3948
- "src/mcp/resources.ts"() {
4149
+ var init_sessions = __esm({
4150
+ "src/mcp/resources/sessions.ts"() {
3949
4151
  "use strict";
3950
- init_logger();
3951
4152
  init_config();
3952
- init_config_utils();
3953
- init_detection();
3954
4153
  init_detection_service();
3955
- init_rag();
3956
- init_indexing_jobs();
3957
- init_context_extractor();
3958
- init_dependency_graph();
3959
- init_symbol_extractor();
3960
- init_paths();
3961
- INDEXABLE_EXTENSIONS = [
3962
- ".ts",
3963
- ".tsx",
3964
- ".js",
3965
- ".jsx",
3966
- ".mjs",
3967
- ".cjs",
3968
- ".py",
3969
- ".pyw",
3970
- ".go",
3971
- ".rs",
3972
- ".java",
3973
- ".kt",
3974
- ".kts",
3975
- ".c",
3976
- ".cpp",
3977
- ".h",
3978
- ".hpp",
3979
- ".cs",
3980
- ".rb",
3981
- ".php",
3982
- ".swift",
3983
- ".md",
3984
- ".mdx",
3985
- ".json",
3986
- ".yaml",
3987
- ".yml",
3988
- ".toml",
3989
- ".sh",
3990
- ".bash",
3991
- ".zsh",
3992
- ".sql",
3993
- ".html",
3994
- ".css",
3995
- ".scss",
3996
- ".sass",
3997
- ".less"
3998
- ];
3999
- CODE_EXTENSIONS = [
4000
- ".ts",
4001
- ".tsx",
4002
- ".js",
4003
- ".jsx",
4004
- ".mjs",
4005
- ".cjs",
4006
- ".py",
4007
- ".pyw",
4008
- ".go",
4009
- ".rs",
4010
- ".java",
4011
- ".kt",
4012
- ".kts",
4013
- ".c",
4014
- ".cpp",
4015
- ".h",
4016
- ".hpp",
4017
- ".cs",
4018
- ".rb",
4019
- ".php",
4020
- ".swift",
4021
- ".sh",
4022
- ".bash",
4023
- ".zsh",
4024
- ".sql"
4025
- ];
4026
- SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv", "target", "vendor"];
4154
+ }
4155
+ });
4156
+
4157
+ // src/mcp/resources/index.ts
4158
+ var init_resources = __esm({
4159
+ "src/mcp/resources/index.ts"() {
4160
+ "use strict";
4161
+ init_types2();
4162
+ init_constants();
4163
+ init_utils2();
4164
+ init_paths2();
4165
+ init_projects();
4166
+ init_tasks();
4167
+ init_search();
4168
+ init_indexing();
4169
+ init_context();
4170
+ init_validation();
4171
+ init_sessions();
4172
+ }
4173
+ });
4174
+
4175
+ // src/mcp/resources.ts
4176
+ var init_resources2 = __esm({
4177
+ "src/mcp/resources.ts"() {
4178
+ "use strict";
4179
+ init_resources();
4027
4180
  }
4028
4181
  });
4029
4182
 
@@ -4101,25 +4254,25 @@ function registerResourceHandlers(server) {
4101
4254
  }
4102
4255
  });
4103
4256
  }
4104
- var init_resources2 = __esm({
4257
+ var init_resources3 = __esm({
4105
4258
  "src/mcp/handlers/resources.ts"() {
4106
4259
  "use strict";
4107
4260
  init_logger();
4108
4261
  init_config();
4109
- init_resources();
4262
+ init_resources2();
4110
4263
  }
4111
4264
  });
4112
4265
 
4113
4266
  // src/mcp/prompts.ts
4114
- import * as path18 from "path";
4115
- import * as fs16 from "fs";
4267
+ import * as path24 from "path";
4268
+ import * as fs22 from "fs";
4116
4269
  function loadBaseProtocol2() {
4117
4270
  if (baseProtocolCache !== null) {
4118
4271
  return baseProtocolCache;
4119
4272
  }
4120
- const basePath = path18.join(getAgentCorePromptsDir(), "_base.md");
4121
- if (fs16.existsSync(basePath)) {
4122
- const content = fs16.readFileSync(basePath, "utf-8");
4273
+ const basePath = path24.join(getAgentCorePromptsDir(), "_base.md");
4274
+ if (fs22.existsSync(basePath)) {
4275
+ const content = fs22.readFileSync(basePath, "utf-8");
4123
4276
  baseProtocolCache = content.replace(/^---[\s\S]*?---\n*/, "");
4124
4277
  return baseProtocolCache;
4125
4278
  }
@@ -4182,15 +4335,15 @@ function renderPromptWithContext(content, args) {
4182
4335
  resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
4183
4336
  resolvedWorkspaceName = activeProject.name;
4184
4337
  if (activeProject.source === "global") {
4185
- const workspacesDir = path18.dirname(activeProject.dataPath);
4186
- resolvedRrceHome = path18.dirname(workspacesDir);
4338
+ const workspacesDir = path24.dirname(activeProject.dataPath);
4339
+ resolvedRrceHome = path24.dirname(workspacesDir);
4187
4340
  }
4188
4341
  } else {
4189
4342
  try {
4190
4343
  const workspaceRoot = detectWorkspaceRoot();
4191
- const workspaceName = path18.basename(workspaceRoot);
4192
- const globalWorkspacePath = path18.join(DEFAULT_RRCE_HOME, "workspaces", workspaceName);
4193
- if (fs16.existsSync(globalWorkspacePath)) {
4344
+ const workspaceName = path24.basename(workspaceRoot);
4345
+ const globalWorkspacePath = path24.join(DEFAULT_RRCE_HOME, "workspaces", workspaceName);
4346
+ if (fs22.existsSync(globalWorkspacePath)) {
4194
4347
  resolvedRrceData = globalWorkspacePath;
4195
4348
  resolvedWorkspaceRoot = workspaceRoot;
4196
4349
  resolvedWorkspaceName = workspaceName;
@@ -4231,7 +4384,7 @@ var init_prompts2 = __esm({
4231
4384
  "src/mcp/prompts.ts"() {
4232
4385
  "use strict";
4233
4386
  init_prompts();
4234
- init_resources();
4387
+ init_resources2();
4235
4388
  init_paths();
4236
4389
  init_detection_service();
4237
4390
  baseProtocolCache = null;
@@ -4792,7 +4945,7 @@ var init_tools = __esm({
4792
4945
  "src/mcp/handlers/tools.ts"() {
4793
4946
  "use strict";
4794
4947
  init_logger();
4795
- init_resources();
4948
+ init_resources2();
4796
4949
  init_prompts2();
4797
4950
  }
4798
4951
  });
@@ -4860,7 +5013,7 @@ var init_prompts3 = __esm({
4860
5013
  "src/mcp/handlers/prompts.ts"() {
4861
5014
  "use strict";
4862
5015
  init_logger();
4863
- init_resources();
5016
+ init_resources2();
4864
5017
  init_prompts2();
4865
5018
  init_paths();
4866
5019
  }
@@ -4928,8 +5081,8 @@ var init_server = __esm({
4928
5081
  "use strict";
4929
5082
  init_logger();
4930
5083
  init_config();
4931
- init_resources();
4932
5084
  init_resources2();
5085
+ init_resources3();
4933
5086
  init_tools();
4934
5087
  init_prompts3();
4935
5088
  serverState = { running: false };
@@ -5019,8 +5172,8 @@ Hidden projects: ${projects.length - exposedCount}`,
5019
5172
  }
5020
5173
  async function handleConfigureGlobalPath() {
5021
5174
  const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
5022
- const fs27 = await import("fs");
5023
- const path26 = await import("path");
5175
+ const fs33 = await import("fs");
5176
+ const path32 = await import("path");
5024
5177
  note3(
5025
5178
  `MCP Hub requires a ${pc5.bold("global storage path")} to store its configuration
5026
5179
  and coordinate across projects.
@@ -5034,8 +5187,8 @@ locally in each project. MCP needs a central location.`,
5034
5187
  return false;
5035
5188
  }
5036
5189
  try {
5037
- if (!fs27.existsSync(resolvedPath)) {
5038
- fs27.mkdirSync(resolvedPath, { recursive: true });
5190
+ if (!fs33.existsSync(resolvedPath)) {
5191
+ fs33.mkdirSync(resolvedPath, { recursive: true });
5039
5192
  }
5040
5193
  const config = loadMCPConfig();
5041
5194
  saveMCPConfig(config);
@@ -5043,7 +5196,7 @@ locally in each project. MCP needs a central location.`,
5043
5196
  `${pc5.green("\u2713")} Global path configured: ${pc5.cyan(resolvedPath)}
5044
5197
 
5045
5198
  MCP config will be stored at:
5046
- ${path26.join(resolvedPath, "mcp.yaml")}`,
5199
+ ${path32.join(resolvedPath, "mcp.yaml")}`,
5047
5200
  "Configuration Saved"
5048
5201
  );
5049
5202
  return true;
@@ -5140,8 +5293,8 @@ var init_Header = __esm({
5140
5293
  });
5141
5294
 
5142
5295
  // src/lib/drift-service.ts
5143
- import * as fs17 from "fs";
5144
- import * as path19 from "path";
5296
+ import * as fs23 from "fs";
5297
+ import * as path25 from "path";
5145
5298
  import * as crypto2 from "crypto";
5146
5299
  var DriftService;
5147
5300
  var init_drift_service = __esm({
@@ -5150,26 +5303,26 @@ var init_drift_service = __esm({
5150
5303
  DriftService = class {
5151
5304
  static CHECKSUM_FILENAME = ".rrce-checksums.json";
5152
5305
  static calculateHash(filePath) {
5153
- const content = fs17.readFileSync(filePath);
5306
+ const content = fs23.readFileSync(filePath);
5154
5307
  return crypto2.createHash("md5").update(content).digest("hex");
5155
5308
  }
5156
5309
  static getManifestPath(projectPath) {
5157
- return path19.join(projectPath, this.CHECKSUM_FILENAME);
5310
+ return path25.join(projectPath, this.CHECKSUM_FILENAME);
5158
5311
  }
5159
5312
  static loadManifest(projectPath) {
5160
5313
  const manifestPath = this.getManifestPath(projectPath);
5161
- if (!fs17.existsSync(manifestPath)) {
5314
+ if (!fs23.existsSync(manifestPath)) {
5162
5315
  return {};
5163
5316
  }
5164
5317
  try {
5165
- return JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
5318
+ return JSON.parse(fs23.readFileSync(manifestPath, "utf8"));
5166
5319
  } catch (e) {
5167
5320
  return {};
5168
5321
  }
5169
5322
  }
5170
5323
  static saveManifest(projectPath, manifest) {
5171
5324
  const manifestPath = this.getManifestPath(projectPath);
5172
- fs17.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
5325
+ fs23.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
5173
5326
  }
5174
5327
  /**
5175
5328
  * Generates a manifest for the current state of files in the project
@@ -5177,9 +5330,9 @@ var init_drift_service = __esm({
5177
5330
  static generateManifest(projectPath, files) {
5178
5331
  const manifest = {};
5179
5332
  for (const file of files) {
5180
- const fullPath = path19.join(projectPath, file);
5181
- if (fs17.existsSync(fullPath)) {
5182
- const stats = fs17.statSync(fullPath);
5333
+ const fullPath = path25.join(projectPath, file);
5334
+ if (fs23.existsSync(fullPath)) {
5335
+ const stats = fs23.statSync(fullPath);
5183
5336
  manifest[file] = {
5184
5337
  hash: this.calculateHash(fullPath),
5185
5338
  mtime: stats.mtimeMs
@@ -5195,11 +5348,11 @@ var init_drift_service = __esm({
5195
5348
  const manifest = this.loadManifest(projectPath);
5196
5349
  const modifiedFiles = [];
5197
5350
  for (const [relPath, entry] of Object.entries(manifest)) {
5198
- const fullPath = path19.join(projectPath, relPath);
5199
- if (!fs17.existsSync(fullPath)) {
5351
+ const fullPath = path25.join(projectPath, relPath);
5352
+ if (!fs23.existsSync(fullPath)) {
5200
5353
  continue;
5201
5354
  }
5202
- const stats = fs17.statSync(fullPath);
5355
+ const stats = fs23.statSync(fullPath);
5203
5356
  if (stats.mtimeMs === entry.mtime) {
5204
5357
  continue;
5205
5358
  }
@@ -5246,15 +5399,15 @@ __export(ConfigContext_exports, {
5246
5399
  useConfig: () => useConfig
5247
5400
  });
5248
5401
  import { createContext, useContext, useState, useCallback, useMemo, useEffect } from "react";
5249
- import * as fs18 from "fs";
5250
- import * as path20 from "path";
5402
+ import * as fs24 from "fs";
5403
+ import * as path26 from "path";
5251
5404
  import { jsx as jsx2 } from "react/jsx-runtime";
5252
5405
  function getPackageVersion() {
5253
5406
  try {
5254
5407
  const agentCoreDir = getAgentCoreDir();
5255
- const packageJsonPath = path20.join(path20.dirname(agentCoreDir), "package.json");
5256
- if (fs18.existsSync(packageJsonPath)) {
5257
- return JSON.parse(fs18.readFileSync(packageJsonPath, "utf8")).version;
5408
+ const packageJsonPath = path26.join(path26.dirname(agentCoreDir), "package.json");
5409
+ if (fs24.existsSync(packageJsonPath)) {
5410
+ return JSON.parse(fs24.readFileSync(packageJsonPath, "utf8")).version;
5258
5411
  }
5259
5412
  } catch (e) {
5260
5413
  }
@@ -5321,16 +5474,16 @@ var init_ConfigContext = __esm({
5321
5474
  });
5322
5475
 
5323
5476
  // src/mcp/ui/lib/tasks-fs.ts
5324
- import * as fs19 from "fs";
5325
- import * as path21 from "path";
5477
+ import * as fs25 from "fs";
5478
+ import * as path27 from "path";
5326
5479
  function readSession(project, taskSlug) {
5327
5480
  const rrceData = getProjectRRCEData(project);
5328
- const sessionPath = path21.join(rrceData, "tasks", taskSlug, "session.json");
5329
- if (!fs19.existsSync(sessionPath)) {
5481
+ const sessionPath = path27.join(rrceData, "tasks", taskSlug, "session.json");
5482
+ if (!fs25.existsSync(sessionPath)) {
5330
5483
  return null;
5331
5484
  }
5332
5485
  try {
5333
- const raw = fs19.readFileSync(sessionPath, "utf-8");
5486
+ const raw = fs25.readFileSync(sessionPath, "utf-8");
5334
5487
  return JSON.parse(raw);
5335
5488
  } catch {
5336
5489
  return null;
@@ -5343,12 +5496,12 @@ function isSessionStale(session, thresholdMs = SESSION_STALE_THRESHOLD_MS) {
5343
5496
  }
5344
5497
  function readAgentTodos(project, taskSlug) {
5345
5498
  const rrceData = getProjectRRCEData(project);
5346
- const todosPath = path21.join(rrceData, "tasks", taskSlug, "agent-todos.json");
5347
- if (!fs19.existsSync(todosPath)) {
5499
+ const todosPath = path27.join(rrceData, "tasks", taskSlug, "agent-todos.json");
5500
+ if (!fs25.existsSync(todosPath)) {
5348
5501
  return null;
5349
5502
  }
5350
5503
  try {
5351
- const raw = fs19.readFileSync(todosPath, "utf-8");
5504
+ const raw = fs25.readFileSync(todosPath, "utf-8");
5352
5505
  return JSON.parse(raw);
5353
5506
  } catch {
5354
5507
  return null;
@@ -5361,8 +5514,8 @@ function detectStorageModeFromConfig(workspaceRoot) {
5361
5514
  if (configPath.startsWith(rrceHome)) {
5362
5515
  return "global";
5363
5516
  }
5364
- if (fs19.existsSync(configPath)) {
5365
- const content = fs19.readFileSync(configPath, "utf-8");
5517
+ if (fs25.existsSync(configPath)) {
5518
+ const content = fs25.readFileSync(configPath, "utf-8");
5366
5519
  if (content.includes("mode: workspace")) return "workspace";
5367
5520
  if (content.includes("mode: global")) return "global";
5368
5521
  }
@@ -5372,7 +5525,7 @@ function detectStorageModeFromConfig(workspaceRoot) {
5372
5525
  }
5373
5526
  function getEffectiveGlobalBase() {
5374
5527
  const dummy = resolveDataPath("global", "__rrce_dummy__", "");
5375
- return path21.dirname(path21.dirname(dummy));
5528
+ return path27.dirname(path27.dirname(dummy));
5376
5529
  }
5377
5530
  function getProjectRRCEData(project) {
5378
5531
  const workspaceRoot = project.sourcePath || project.path;
@@ -5381,19 +5534,19 @@ function getProjectRRCEData(project) {
5381
5534
  }
5382
5535
  function listProjectTasks(project) {
5383
5536
  const rrceData = getProjectRRCEData(project);
5384
- const tasksPath = path21.join(rrceData, "tasks");
5385
- if (!fs19.existsSync(tasksPath)) {
5537
+ const tasksPath = path27.join(rrceData, "tasks");
5538
+ if (!fs25.existsSync(tasksPath)) {
5386
5539
  return { projectName: project.name, tasksPath, tasks: [] };
5387
5540
  }
5388
5541
  const tasks = [];
5389
5542
  try {
5390
- const entries = fs19.readdirSync(tasksPath, { withFileTypes: true });
5543
+ const entries = fs25.readdirSync(tasksPath, { withFileTypes: true });
5391
5544
  for (const entry of entries) {
5392
5545
  if (!entry.isDirectory()) continue;
5393
- const metaPath = path21.join(tasksPath, entry.name, "meta.json");
5394
- if (!fs19.existsSync(metaPath)) continue;
5546
+ const metaPath = path27.join(tasksPath, entry.name, "meta.json");
5547
+ if (!fs25.existsSync(metaPath)) continue;
5395
5548
  try {
5396
- const raw = fs19.readFileSync(metaPath, "utf-8");
5549
+ const raw = fs25.readFileSync(metaPath, "utf-8");
5397
5550
  const meta = JSON.parse(raw);
5398
5551
  if (!meta.task_slug) meta.task_slug = entry.name;
5399
5552
  tasks.push(meta);
@@ -5412,18 +5565,18 @@ function listProjectTasks(project) {
5412
5565
  }
5413
5566
  function updateTaskStatus(project, taskSlug, status) {
5414
5567
  const rrceData = getProjectRRCEData(project);
5415
- const metaPath = path21.join(rrceData, "tasks", taskSlug, "meta.json");
5416
- if (!fs19.existsSync(metaPath)) {
5568
+ const metaPath = path27.join(rrceData, "tasks", taskSlug, "meta.json");
5569
+ if (!fs25.existsSync(metaPath)) {
5417
5570
  return { ok: false, error: `meta.json not found for task '${taskSlug}'` };
5418
5571
  }
5419
5572
  try {
5420
- const meta = JSON.parse(fs19.readFileSync(metaPath, "utf-8"));
5573
+ const meta = JSON.parse(fs25.readFileSync(metaPath, "utf-8"));
5421
5574
  const next = {
5422
5575
  ...meta,
5423
5576
  status,
5424
5577
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
5425
5578
  };
5426
- fs19.writeFileSync(metaPath, JSON.stringify(next, null, 2));
5579
+ fs25.writeFileSync(metaPath, JSON.stringify(next, null, 2));
5427
5580
  return { ok: true, meta: next };
5428
5581
  } catch (e) {
5429
5582
  return { ok: false, error: String(e) };
@@ -5784,28 +5937,28 @@ var init_project_utils = __esm({
5784
5937
  // src/mcp/ui/ProjectsView.tsx
5785
5938
  import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
5786
5939
  import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
5787
- import * as fs20 from "fs";
5788
- import * as path22 from "path";
5940
+ import * as fs26 from "fs";
5941
+ import * as path28 from "path";
5789
5942
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
5790
5943
  function getIndexStats(project) {
5791
5944
  const stats = { knowledgeCount: 0, codeCount: 0, lastIndexed: null };
5792
5945
  try {
5793
5946
  const knowledgePath = project.knowledgePath;
5794
5947
  if (knowledgePath) {
5795
- const embPath = path22.join(knowledgePath, "embeddings.json");
5796
- const codeEmbPath = path22.join(knowledgePath, "code-embeddings.json");
5797
- if (fs20.existsSync(embPath)) {
5798
- const stat = fs20.statSync(embPath);
5948
+ const embPath = path28.join(knowledgePath, "embeddings.json");
5949
+ const codeEmbPath = path28.join(knowledgePath, "code-embeddings.json");
5950
+ if (fs26.existsSync(embPath)) {
5951
+ const stat = fs26.statSync(embPath);
5799
5952
  stats.lastIndexed = stat.mtime.toISOString();
5800
5953
  try {
5801
- const data = JSON.parse(fs20.readFileSync(embPath, "utf-8"));
5954
+ const data = JSON.parse(fs26.readFileSync(embPath, "utf-8"));
5802
5955
  stats.knowledgeCount = Array.isArray(data) ? data.length : Object.keys(data).length;
5803
5956
  } catch {
5804
5957
  }
5805
5958
  }
5806
- if (fs20.existsSync(codeEmbPath)) {
5959
+ if (fs26.existsSync(codeEmbPath)) {
5807
5960
  try {
5808
- const data = JSON.parse(fs20.readFileSync(codeEmbPath, "utf-8"));
5961
+ const data = JSON.parse(fs26.readFileSync(codeEmbPath, "utf-8"));
5809
5962
  stats.codeCount = Array.isArray(data) ? data.length : Object.keys(data).length;
5810
5963
  } catch {
5811
5964
  }
@@ -6506,7 +6659,7 @@ __export(App_exports, {
6506
6659
  });
6507
6660
  import { useState as useState5, useEffect as useEffect6, useMemo as useMemo5, useCallback as useCallback3 } from "react";
6508
6661
  import { Box as Box11, useInput as useInput5, useApp } from "ink";
6509
- import fs21 from "fs";
6662
+ import fs27 from "fs";
6510
6663
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
6511
6664
  var App;
6512
6665
  var init_App = __esm({
@@ -6579,18 +6732,18 @@ var init_App = __esm({
6579
6732
  useEffect6(() => {
6580
6733
  const logPath = getLogFilePath();
6581
6734
  let lastSize = 0;
6582
- if (fs21.existsSync(logPath)) {
6583
- const stats = fs21.statSync(logPath);
6735
+ if (fs27.existsSync(logPath)) {
6736
+ const stats = fs27.statSync(logPath);
6584
6737
  lastSize = stats.size;
6585
6738
  }
6586
6739
  const interval = setInterval(() => {
6587
- if (fs21.existsSync(logPath)) {
6588
- const stats = fs21.statSync(logPath);
6740
+ if (fs27.existsSync(logPath)) {
6741
+ const stats = fs27.statSync(logPath);
6589
6742
  if (stats.size > lastSize) {
6590
6743
  const buffer = Buffer.alloc(stats.size - lastSize);
6591
- const fd = fs21.openSync(logPath, "r");
6592
- fs21.readSync(fd, buffer, 0, buffer.length, lastSize);
6593
- fs21.closeSync(fd);
6744
+ const fd = fs27.openSync(logPath, "r");
6745
+ fs27.readSync(fd, buffer, 0, buffer.length, lastSize);
6746
+ fs27.closeSync(fd);
6594
6747
  const newContent = buffer.toString("utf-8");
6595
6748
  const newLines = newContent.split("\n").filter((l) => l.trim());
6596
6749
  setLogs((prev) => {
@@ -6815,15 +6968,15 @@ __export(update_flow_exports, {
6815
6968
  });
6816
6969
  import { confirm as confirm5, spinner as spinner2, note as note6, outro as outro2, cancel as cancel2, isCancel as isCancel7 } from "@clack/prompts";
6817
6970
  import pc8 from "picocolors";
6818
- import * as fs22 from "fs";
6819
- import * as path23 from "path";
6971
+ import * as fs28 from "fs";
6972
+ import * as path29 from "path";
6820
6973
  import { stringify as stringify2, parse } from "yaml";
6821
6974
  function backupFile(filePath) {
6822
- if (!fs22.existsSync(filePath)) return null;
6975
+ if (!fs28.existsSync(filePath)) return null;
6823
6976
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T")[0] + "-" + Date.now();
6824
6977
  const backupPath = `${filePath}.${timestamp}.bak`;
6825
6978
  try {
6826
- fs22.copyFileSync(filePath, backupPath);
6979
+ fs28.copyFileSync(filePath, backupPath);
6827
6980
  return backupPath;
6828
6981
  } catch (e) {
6829
6982
  console.error(`Failed to backup ${filePath}:`, e);
@@ -6833,9 +6986,9 @@ function backupFile(filePath) {
6833
6986
  function getPackageVersion2() {
6834
6987
  try {
6835
6988
  const agentCoreDir = getAgentCoreDir();
6836
- const packageJsonPath = path23.join(path23.dirname(agentCoreDir), "package.json");
6837
- if (fs22.existsSync(packageJsonPath)) {
6838
- return JSON.parse(fs22.readFileSync(packageJsonPath, "utf8")).version;
6989
+ const packageJsonPath = path29.join(path29.dirname(agentCoreDir), "package.json");
6990
+ if (fs28.existsSync(packageJsonPath)) {
6991
+ return JSON.parse(fs28.readFileSync(packageJsonPath, "utf8")).version;
6839
6992
  }
6840
6993
  } catch (e) {
6841
6994
  }
@@ -6850,9 +7003,9 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
6850
7003
  const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
6851
7004
  const configFilePath = getConfigPath(workspacePath);
6852
7005
  let currentSyncedVersion;
6853
- if (fs22.existsSync(configFilePath)) {
7006
+ if (fs28.existsSync(configFilePath)) {
6854
7007
  try {
6855
- const content = fs22.readFileSync(configFilePath, "utf-8");
7008
+ const content = fs28.readFileSync(configFilePath, "utf-8");
6856
7009
  const config = parse(content);
6857
7010
  currentSyncedVersion = config.last_synced_version;
6858
7011
  } catch (e) {
@@ -6860,8 +7013,8 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
6860
7013
  }
6861
7014
  const driftReport = DriftService.checkDrift(dataPaths[0], currentSyncedVersion, runningVersion);
6862
7015
  const ideTargets = [];
6863
- if (fs22.existsSync(configFilePath)) {
6864
- const configContent = fs22.readFileSync(configFilePath, "utf-8");
7016
+ if (fs28.existsSync(configFilePath)) {
7017
+ const configContent = fs28.readFileSync(configFilePath, "utf-8");
6865
7018
  if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
6866
7019
  if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
6867
7020
  if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
@@ -6870,14 +7023,14 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
6870
7023
  const dirs = ["templates", "prompts", "docs"];
6871
7024
  const updatedFiles = [];
6872
7025
  for (const dir of dirs) {
6873
- const srcDir = path23.join(agentCoreDir, dir);
6874
- if (!fs22.existsSync(srcDir)) continue;
7026
+ const srcDir = path29.join(agentCoreDir, dir);
7027
+ if (!fs28.existsSync(srcDir)) continue;
6875
7028
  const syncFiles = (src, rel) => {
6876
- const entries = fs22.readdirSync(src, { withFileTypes: true });
7029
+ const entries = fs28.readdirSync(src, { withFileTypes: true });
6877
7030
  for (const entry of entries) {
6878
- const entrySrc = path23.join(src, entry.name);
6879
- const entryRel = path23.join(rel, entry.name);
6880
- const entryDest = path23.join(dataPath, entryRel);
7031
+ const entrySrc = path29.join(src, entry.name);
7032
+ const entryRel = path29.join(rel, entry.name);
7033
+ const entryDest = path29.join(dataPath, entryRel);
6881
7034
  if (entry.isDirectory()) {
6882
7035
  ensureDir(entryDest);
6883
7036
  syncFiles(entrySrc, entryRel);
@@ -6885,8 +7038,8 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
6885
7038
  if (driftReport.modifiedFiles.includes(entryRel)) {
6886
7039
  backupFile(entryDest);
6887
7040
  }
6888
- ensureDir(path23.dirname(entryDest));
6889
- fs22.copyFileSync(entrySrc, entryDest);
7041
+ ensureDir(path29.dirname(entryDest));
7042
+ fs28.copyFileSync(entrySrc, entryDest);
6890
7043
  updatedFiles.push(entryRel);
6891
7044
  }
6892
7045
  }
@@ -6897,12 +7050,12 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
6897
7050
  DriftService.saveManifest(dataPath, manifest);
6898
7051
  }
6899
7052
  const rrceHome = customGlobalPath || getDefaultRRCEHome2();
6900
- ensureDir(path23.join(rrceHome, "templates"));
6901
- ensureDir(path23.join(rrceHome, "docs"));
6902
- copyDirRecursive(path23.join(agentCoreDir, "templates"), path23.join(rrceHome, "templates"));
6903
- copyDirRecursive(path23.join(agentCoreDir, "docs"), path23.join(rrceHome, "docs"));
6904
- if (fs22.existsSync(configFilePath)) {
6905
- const configContent = fs22.readFileSync(configFilePath, "utf-8");
7053
+ ensureDir(path29.join(rrceHome, "templates"));
7054
+ ensureDir(path29.join(rrceHome, "docs"));
7055
+ copyDirRecursive(path29.join(agentCoreDir, "templates"), path29.join(rrceHome, "templates"));
7056
+ copyDirRecursive(path29.join(agentCoreDir, "docs"), path29.join(rrceHome, "docs"));
7057
+ if (fs28.existsSync(configFilePath)) {
7058
+ const configContent = fs28.readFileSync(configFilePath, "utf-8");
6906
7059
  if (configContent.includes("copilot: true")) {
6907
7060
  const copilotPath = getAgentPromptPath(workspacePath, "copilot");
6908
7061
  ensureDir(copilotPath);
@@ -6924,21 +7077,21 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
6924
7077
  try {
6925
7078
  const yaml = parse(configContent);
6926
7079
  yaml.last_synced_version = runningVersion;
6927
- fs22.writeFileSync(configFilePath, stringify2(yaml));
7080
+ fs28.writeFileSync(configFilePath, stringify2(yaml));
6928
7081
  } catch (e) {
6929
7082
  console.error("Failed to update config.yaml version:", e);
6930
7083
  }
6931
7084
  }
6932
- const mcpPath = path23.join(rrceHome, "mcp.yaml");
6933
- if (fs22.existsSync(mcpPath)) {
7085
+ const mcpPath = path29.join(rrceHome, "mcp.yaml");
7086
+ if (fs28.existsSync(mcpPath)) {
6934
7087
  try {
6935
- const content = fs22.readFileSync(mcpPath, "utf-8");
7088
+ const content = fs28.readFileSync(mcpPath, "utf-8");
6936
7089
  const yaml = parse(content);
6937
7090
  if (yaml.projects) {
6938
7091
  const project = yaml.projects.find((p) => p.name === workspaceName);
6939
7092
  if (project) {
6940
7093
  project.last_synced_version = runningVersion;
6941
- fs22.writeFileSync(mcpPath, stringify2(yaml));
7094
+ fs28.writeFileSync(mcpPath, stringify2(yaml));
6942
7095
  }
6943
7096
  }
6944
7097
  } catch (e) {
@@ -6974,9 +7127,9 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
6974
7127
  const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
6975
7128
  const configFilePath = getConfigPath(workspacePath);
6976
7129
  let currentSyncedVersion;
6977
- if (fs22.existsSync(configFilePath)) {
7130
+ if (fs28.existsSync(configFilePath)) {
6978
7131
  try {
6979
- const content = fs22.readFileSync(configFilePath, "utf-8");
7132
+ const content = fs28.readFileSync(configFilePath, "utf-8");
6980
7133
  const config = parse(content);
6981
7134
  currentSyncedVersion = config.last_synced_version;
6982
7135
  } catch (e) {
@@ -7000,8 +7153,8 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
7000
7153
  ` \u2022 docs/ (documentation)`
7001
7154
  ];
7002
7155
  const ideTargets = [];
7003
- if (fs22.existsSync(configFilePath)) {
7004
- const configContent = fs22.readFileSync(configFilePath, "utf-8");
7156
+ if (fs28.existsSync(configFilePath)) {
7157
+ const configContent = fs28.readFileSync(configFilePath, "utf-8");
7005
7158
  if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
7006
7159
  if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
7007
7160
  if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
@@ -7030,14 +7183,14 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7030
7183
  const dirs = ["templates", "prompts", "docs"];
7031
7184
  const updatedFiles = [];
7032
7185
  for (const dir of dirs) {
7033
- const srcDir = path23.join(agentCoreDir, dir);
7034
- if (!fs22.existsSync(srcDir)) continue;
7186
+ const srcDir = path29.join(agentCoreDir, dir);
7187
+ if (!fs28.existsSync(srcDir)) continue;
7035
7188
  const syncFiles = (src, rel) => {
7036
- const entries = fs22.readdirSync(src, { withFileTypes: true });
7189
+ const entries = fs28.readdirSync(src, { withFileTypes: true });
7037
7190
  for (const entry of entries) {
7038
- const entrySrc = path23.join(src, entry.name);
7039
- const entryRel = path23.join(rel, entry.name);
7040
- const entryDest = path23.join(dataPath, entryRel);
7191
+ const entrySrc = path29.join(src, entry.name);
7192
+ const entryRel = path29.join(rel, entry.name);
7193
+ const entryDest = path29.join(dataPath, entryRel);
7041
7194
  if (entry.isDirectory()) {
7042
7195
  ensureDir(entryDest);
7043
7196
  syncFiles(entrySrc, entryRel);
@@ -7045,8 +7198,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7045
7198
  if (driftReport.modifiedFiles.includes(entryRel)) {
7046
7199
  backupFile(entryDest);
7047
7200
  }
7048
- ensureDir(path23.dirname(entryDest));
7049
- fs22.copyFileSync(entrySrc, entryDest);
7201
+ ensureDir(path29.dirname(entryDest));
7202
+ fs28.copyFileSync(entrySrc, entryDest);
7050
7203
  updatedFiles.push(entryRel);
7051
7204
  }
7052
7205
  }
@@ -7057,12 +7210,12 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7057
7210
  DriftService.saveManifest(dataPath, manifest);
7058
7211
  }
7059
7212
  const rrceHome = customGlobalPath || getDefaultRRCEHome2();
7060
- ensureDir(path23.join(rrceHome, "templates"));
7061
- ensureDir(path23.join(rrceHome, "docs"));
7062
- copyDirRecursive(path23.join(agentCoreDir, "templates"), path23.join(rrceHome, "templates"));
7063
- copyDirRecursive(path23.join(agentCoreDir, "docs"), path23.join(rrceHome, "docs"));
7064
- if (fs22.existsSync(configFilePath)) {
7065
- const configContent = fs22.readFileSync(configFilePath, "utf-8");
7213
+ ensureDir(path29.join(rrceHome, "templates"));
7214
+ ensureDir(path29.join(rrceHome, "docs"));
7215
+ copyDirRecursive(path29.join(agentCoreDir, "templates"), path29.join(rrceHome, "templates"));
7216
+ copyDirRecursive(path29.join(agentCoreDir, "docs"), path29.join(rrceHome, "docs"));
7217
+ if (fs28.existsSync(configFilePath)) {
7218
+ const configContent = fs28.readFileSync(configFilePath, "utf-8");
7066
7219
  if (configContent.includes("copilot: true")) {
7067
7220
  const copilotPath = getAgentPromptPath(workspacePath, "copilot");
7068
7221
  ensureDir(copilotPath);
@@ -7084,21 +7237,21 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7084
7237
  try {
7085
7238
  const yaml = parse(configContent);
7086
7239
  yaml.last_synced_version = runningVersion;
7087
- fs22.writeFileSync(configFilePath, stringify2(yaml));
7240
+ fs28.writeFileSync(configFilePath, stringify2(yaml));
7088
7241
  } catch (e) {
7089
7242
  console.error("Failed to update config.yaml version:", e);
7090
7243
  }
7091
7244
  }
7092
- const mcpPath = path23.join(rrceHome, "mcp.yaml");
7093
- if (fs22.existsSync(mcpPath)) {
7245
+ const mcpPath = path29.join(rrceHome, "mcp.yaml");
7246
+ if (fs28.existsSync(mcpPath)) {
7094
7247
  try {
7095
- const content = fs22.readFileSync(mcpPath, "utf-8");
7248
+ const content = fs28.readFileSync(mcpPath, "utf-8");
7096
7249
  const yaml = parse(content);
7097
7250
  if (yaml.projects) {
7098
7251
  const project = yaml.projects.find((p) => p.name === workspaceName);
7099
7252
  if (project) {
7100
7253
  project.last_synced_version = runningVersion;
7101
- fs22.writeFileSync(mcpPath, stringify2(yaml));
7254
+ fs28.writeFileSync(mcpPath, stringify2(yaml));
7102
7255
  }
7103
7256
  }
7104
7257
  } catch (e) {
@@ -7133,8 +7286,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7133
7286
  }
7134
7287
  }
7135
7288
  function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
7136
- const globalPath = path23.join(customGlobalPath, "workspaces", workspaceName);
7137
- const workspacePath = path23.join(workspaceRoot, ".rrce-workflow");
7289
+ const globalPath = path29.join(customGlobalPath, "workspaces", workspaceName);
7290
+ const workspacePath = path29.join(workspaceRoot, ".rrce-workflow");
7138
7291
  switch (mode) {
7139
7292
  case "global":
7140
7293
  return [globalPath];
@@ -7157,8 +7310,8 @@ var init_update_flow = __esm({
7157
7310
  // src/commands/wizard/index.ts
7158
7311
  import { intro as intro2, select as select5, spinner as spinner7, note as note11, outro as outro7, isCancel as isCancel12, confirm as confirm10 } from "@clack/prompts";
7159
7312
  import pc13 from "picocolors";
7160
- import * as fs26 from "fs";
7161
- import * as path25 from "path";
7313
+ import * as fs32 from "fs";
7314
+ import * as path31 from "path";
7162
7315
  import { parse as parse2 } from "yaml";
7163
7316
 
7164
7317
  // src/lib/git.ts
@@ -7835,7 +7988,7 @@ async function handlePostSetup(config, workspacePath, workspaceName, linkedProje
7835
7988
  init_paths();
7836
7989
  import { multiselect as multiselect4, spinner as spinner4, note as note8, outro as outro4, cancel as cancel4, isCancel as isCancel9, confirm as confirm7 } from "@clack/prompts";
7837
7990
  import pc10 from "picocolors";
7838
- import * as fs23 from "fs";
7991
+ import * as fs29 from "fs";
7839
7992
  init_detection();
7840
7993
  async function runLinkProjectsFlow(workspacePath, workspaceName) {
7841
7994
  const projects = scanForProjects({
@@ -7874,7 +8027,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
7874
8027
  const s = spinner4();
7875
8028
  s.start("Linking projects");
7876
8029
  const configFilePath = getConfigPath(workspacePath);
7877
- let configContent = fs23.readFileSync(configFilePath, "utf-8");
8030
+ let configContent = fs29.readFileSync(configFilePath, "utf-8");
7878
8031
  if (configContent.includes("linked_projects:")) {
7879
8032
  const lines = configContent.split("\n");
7880
8033
  const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
@@ -7901,7 +8054,7 @@ linked_projects:
7901
8054
  `;
7902
8055
  });
7903
8056
  }
7904
- fs23.writeFileSync(configFilePath, configContent);
8057
+ fs29.writeFileSync(configFilePath, configContent);
7905
8058
  generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
7906
8059
  s.stop("Projects linked");
7907
8060
  const workspaceFile = `${workspaceName}.code-workspace`;
@@ -7937,15 +8090,15 @@ init_paths();
7937
8090
  init_utils();
7938
8091
  import { confirm as confirm8, spinner as spinner5, note as note9, outro as outro5, cancel as cancel5, isCancel as isCancel10 } from "@clack/prompts";
7939
8092
  import pc11 from "picocolors";
7940
- import * as fs24 from "fs";
7941
- import * as path24 from "path";
8093
+ import * as fs30 from "fs";
8094
+ import * as path30 from "path";
7942
8095
  async function runSyncToGlobalFlow(workspacePath, workspaceName) {
7943
8096
  const localPath = getLocalWorkspacePath(workspacePath);
7944
8097
  const customGlobalPath = getEffectiveRRCEHome(workspacePath);
7945
- const globalPath = path24.join(customGlobalPath, "workspaces", workspaceName);
8098
+ const globalPath = path30.join(customGlobalPath, "workspaces", workspaceName);
7946
8099
  const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
7947
8100
  const existingDirs = subdirs.filter(
7948
- (dir) => fs24.existsSync(path24.join(localPath, dir))
8101
+ (dir) => fs30.existsSync(path30.join(localPath, dir))
7949
8102
  );
7950
8103
  if (existingDirs.length === 0) {
7951
8104
  outro5(pc11.yellow("No data found in workspace storage to sync."));
@@ -7971,8 +8124,8 @@ Destination: ${pc11.cyan(globalPath)}`,
7971
8124
  try {
7972
8125
  ensureDir(globalPath);
7973
8126
  for (const dir of existingDirs) {
7974
- const srcDir = path24.join(localPath, dir);
7975
- const destDir = path24.join(globalPath, dir);
8127
+ const srcDir = path30.join(localPath, dir);
8128
+ const destDir = path30.join(globalPath, dir);
7976
8129
  ensureDir(destDir);
7977
8130
  copyDirRecursive(srcDir, destDir);
7978
8131
  }
@@ -8000,7 +8153,7 @@ init_update_flow();
8000
8153
  // src/commands/wizard/delete-flow.ts
8001
8154
  import { multiselect as multiselect5, confirm as confirm9, spinner as spinner6, note as note10, cancel as cancel6, isCancel as isCancel11 } from "@clack/prompts";
8002
8155
  import pc12 from "picocolors";
8003
- import * as fs25 from "fs";
8156
+ import * as fs31 from "fs";
8004
8157
  init_detection();
8005
8158
  init_config();
8006
8159
  async function runDeleteGlobalProjectFlow(availableProjects) {
@@ -8044,8 +8197,8 @@ Are you sure?`,
8044
8197
  for (const projectName of projectsToDelete) {
8045
8198
  const project = globalProjects.find((p) => p.name === projectName);
8046
8199
  if (!project) continue;
8047
- if (fs25.existsSync(project.dataPath)) {
8048
- fs25.rmSync(project.dataPath, { recursive: true, force: true });
8200
+ if (fs31.existsSync(project.dataPath)) {
8201
+ fs31.rmSync(project.dataPath, { recursive: true, force: true });
8049
8202
  }
8050
8203
  const newConfig = removeProjectConfig(mcpConfig, projectName);
8051
8204
  configChanged = true;
@@ -8067,9 +8220,9 @@ init_config();
8067
8220
  function getPackageVersion3() {
8068
8221
  try {
8069
8222
  const agentCoreDir = getAgentCoreDir();
8070
- const packageJsonPath = path25.join(path25.dirname(agentCoreDir), "package.json");
8071
- if (fs26.existsSync(packageJsonPath)) {
8072
- return JSON.parse(fs26.readFileSync(packageJsonPath, "utf8")).version;
8223
+ const packageJsonPath = path31.join(path31.dirname(agentCoreDir), "package.json");
8224
+ if (fs32.existsSync(packageJsonPath)) {
8225
+ return JSON.parse(fs32.readFileSync(packageJsonPath, "utf8")).version;
8073
8226
  }
8074
8227
  } catch (e) {
8075
8228
  }
@@ -8077,9 +8230,9 @@ function getPackageVersion3() {
8077
8230
  }
8078
8231
  function getLastSyncedVersion(workspacePath, workspaceName) {
8079
8232
  const configFilePath = getConfigPath(workspacePath);
8080
- if (fs26.existsSync(configFilePath)) {
8233
+ if (fs32.existsSync(configFilePath)) {
8081
8234
  try {
8082
- const content = fs26.readFileSync(configFilePath, "utf-8");
8235
+ const content = fs32.readFileSync(configFilePath, "utf-8");
8083
8236
  const config = parse2(content);
8084
8237
  if (config.last_synced_version) {
8085
8238
  return config.last_synced_version;
@@ -8088,10 +8241,10 @@ function getLastSyncedVersion(workspacePath, workspaceName) {
8088
8241
  }
8089
8242
  }
8090
8243
  const rrceHome = getEffectiveRRCEHome(workspacePath) || getDefaultRRCEHome2();
8091
- const mcpPath = path25.join(rrceHome, "mcp.yaml");
8092
- if (fs26.existsSync(mcpPath)) {
8244
+ const mcpPath = path31.join(rrceHome, "mcp.yaml");
8245
+ if (fs32.existsSync(mcpPath)) {
8093
8246
  try {
8094
- const content = fs26.readFileSync(mcpPath, "utf-8");
8247
+ const content = fs32.readFileSync(mcpPath, "utf-8");
8095
8248
  const config = parse2(content);
8096
8249
  const project = config.projects?.find((p) => p.name === workspaceName);
8097
8250
  if (project?.last_synced_version) {
@@ -8161,11 +8314,11 @@ Workspace: ${pc13.bold(workspaceName)}`,
8161
8314
  workspacePath
8162
8315
  });
8163
8316
  const configFilePath = getConfigPath(workspacePath);
8164
- let isAlreadyConfigured = fs26.existsSync(configFilePath);
8317
+ let isAlreadyConfigured = fs32.existsSync(configFilePath);
8165
8318
  let currentStorageMode = null;
8166
8319
  if (isAlreadyConfigured) {
8167
8320
  try {
8168
- const configContent = fs26.readFileSync(configFilePath, "utf-8");
8321
+ const configContent = fs32.readFileSync(configFilePath, "utf-8");
8169
8322
  const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
8170
8323
  currentStorageMode = modeMatch?.[1] ?? null;
8171
8324
  } catch {
@@ -8182,7 +8335,7 @@ Workspace: ${pc13.bold(workspaceName)}`,
8182
8335
  }
8183
8336
  }
8184
8337
  const localDataPath = getLocalWorkspacePath(workspacePath);
8185
- const hasLocalData = fs26.existsSync(localDataPath);
8338
+ const hasLocalData = fs32.existsSync(localDataPath);
8186
8339
  if (isAlreadyConfigured) {
8187
8340
  const continueToMenu = await checkAndPromptUpdate(workspacePath, workspaceName, currentStorageMode);
8188
8341
  if (!continueToMenu) {