rrce-workflow 0.2.72 → 0.2.73

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.
Files changed (2) hide show
  1. package/dist/index.js +158 -114
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1390,7 +1390,7 @@ var init_types = __esm({
1390
1390
  },
1391
1391
  projects: [],
1392
1392
  defaults: {
1393
- includeNew: true,
1393
+ includeNew: false,
1394
1394
  permissions: {
1395
1395
  knowledge: true,
1396
1396
  tasks: true,
@@ -1407,15 +1407,27 @@ var init_types = __esm({
1407
1407
  });
1408
1408
 
1409
1409
  // src/mcp/config-utils.ts
1410
+ import * as path10 from "path";
1411
+ function normalizeProjectPath(projectPath) {
1412
+ if (projectPath.endsWith(".rrce-workflow")) {
1413
+ return path10.dirname(projectPath);
1414
+ }
1415
+ if (projectPath.endsWith(".rrce-workflow/")) {
1416
+ return path10.dirname(projectPath.slice(0, -1));
1417
+ }
1418
+ return projectPath;
1419
+ }
1410
1420
  function findProjectConfig(config, identifier) {
1421
+ const targetPath = identifier.path ? normalizeProjectPath(identifier.path) : void 0;
1411
1422
  return config.projects.find((p) => {
1412
- if (identifier.path && p.path) {
1413
- return p.path === identifier.path;
1423
+ const configPath = p.path ? normalizeProjectPath(p.path) : void 0;
1424
+ if (targetPath && configPath) {
1425
+ return configPath === targetPath;
1414
1426
  }
1415
- if (!identifier.path && !p.path) {
1427
+ if (!targetPath && !configPath) {
1416
1428
  return p.name === identifier.name;
1417
1429
  }
1418
- if (identifier.path && !p.path) {
1430
+ if (targetPath && !configPath) {
1419
1431
  return p.name === identifier.name;
1420
1432
  }
1421
1433
  return false;
@@ -1441,18 +1453,46 @@ __export(config_exports, {
1441
1453
  setProjectConfig: () => setProjectConfig
1442
1454
  });
1443
1455
  import * as fs9 from "fs";
1444
- import * as path10 from "path";
1456
+ import * as path11 from "path";
1445
1457
  import YAML from "yaml";
1458
+ function migrateConfig(config) {
1459
+ let changed = false;
1460
+ config.projects = config.projects.map((p) => {
1461
+ if (p.path) {
1462
+ const normalized = normalizeProjectPath(p.path);
1463
+ if (normalized !== p.path) {
1464
+ changed = true;
1465
+ return { ...p, path: normalized };
1466
+ }
1467
+ }
1468
+ return p;
1469
+ });
1470
+ return config;
1471
+ }
1446
1472
  function getMCPConfigPath() {
1447
1473
  const workspaceRoot = detectWorkspaceRoot();
1448
1474
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1449
- return path10.join(rrceHome, "mcp.yaml");
1475
+ return path11.join(rrceHome, "mcp.yaml");
1476
+ }
1477
+ function loadMCPConfig() {
1478
+ const configPath = getMCPConfigPath();
1479
+ if (!fs9.existsSync(configPath)) {
1480
+ return { ...DEFAULT_MCP_CONFIG };
1481
+ }
1482
+ try {
1483
+ const content = fs9.readFileSync(configPath, "utf-8");
1484
+ let config = parseMCPConfig(content);
1485
+ config = migrateConfig(config);
1486
+ return config;
1487
+ } catch {
1488
+ return { ...DEFAULT_MCP_CONFIG };
1489
+ }
1450
1490
  }
1451
1491
  function ensureMCPGlobalPath() {
1452
1492
  const workspaceRoot = detectWorkspaceRoot();
1453
1493
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1454
1494
  if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
1455
- const configPath = path10.join(workspaceRoot, ".rrce-workflow", "config.yaml");
1495
+ const configPath = path11.join(workspaceRoot, ".rrce-workflow", "config.yaml");
1456
1496
  if (fs9.existsSync(configPath)) {
1457
1497
  const content = fs9.readFileSync(configPath, "utf-8");
1458
1498
  const modeMatch = content.match(/mode:\s*(global|workspace)/);
@@ -1470,21 +1510,9 @@ function ensureMCPGlobalPath() {
1470
1510
  path: rrceHome
1471
1511
  };
1472
1512
  }
1473
- function loadMCPConfig() {
1474
- const configPath = getMCPConfigPath();
1475
- if (!fs9.existsSync(configPath)) {
1476
- return { ...DEFAULT_MCP_CONFIG };
1477
- }
1478
- try {
1479
- const content = fs9.readFileSync(configPath, "utf-8");
1480
- return parseMCPConfig(content);
1481
- } catch {
1482
- return { ...DEFAULT_MCP_CONFIG };
1483
- }
1484
- }
1485
1513
  function saveMCPConfig(config) {
1486
1514
  const configPath = getMCPConfigPath();
1487
- const dir = path10.dirname(configPath);
1515
+ const dir = path11.dirname(configPath);
1488
1516
  if (!fs9.existsSync(dir)) {
1489
1517
  fs9.mkdirSync(dir, { recursive: true });
1490
1518
  }
@@ -1576,7 +1604,7 @@ function getProjectPermissions(config, name, projectPath) {
1576
1604
  }
1577
1605
  function cleanStaleProjects(config) {
1578
1606
  const rrceHome = getEffectiveGlobalPath();
1579
- const globalWorkspacesDir = path10.join(rrceHome, "workspaces");
1607
+ const globalWorkspacesDir = path11.join(rrceHome, "workspaces");
1580
1608
  const validProjects = [];
1581
1609
  const removed = [];
1582
1610
  for (const project of config.projects) {
@@ -1584,7 +1612,7 @@ function cleanStaleProjects(config) {
1584
1612
  if (project.path) {
1585
1613
  exists = fs9.existsSync(project.path);
1586
1614
  } else {
1587
- const globalPath = path10.join(globalWorkspacesDir, project.name);
1615
+ const globalPath = path11.join(globalWorkspacesDir, project.name);
1588
1616
  exists = fs9.existsSync(globalPath);
1589
1617
  }
1590
1618
  if (exists) {
@@ -1609,29 +1637,29 @@ var init_config = __esm({
1609
1637
 
1610
1638
  // src/commands/wizard/setup-actions.ts
1611
1639
  import * as fs10 from "fs";
1612
- import * as path11 from "path";
1640
+ import * as path12 from "path";
1613
1641
  import pc4 from "picocolors";
1614
1642
  import { note as note2 } from "@clack/prompts";
1615
1643
  function createDirectoryStructure(dataPaths) {
1616
1644
  for (const dataPath of dataPaths) {
1617
1645
  ensureDir(dataPath);
1618
- ensureDir(path11.join(dataPath, "knowledge"));
1619
- ensureDir(path11.join(dataPath, "refs"));
1620
- ensureDir(path11.join(dataPath, "tasks"));
1621
- ensureDir(path11.join(dataPath, "templates"));
1646
+ ensureDir(path12.join(dataPath, "knowledge"));
1647
+ ensureDir(path12.join(dataPath, "refs"));
1648
+ ensureDir(path12.join(dataPath, "tasks"));
1649
+ ensureDir(path12.join(dataPath, "templates"));
1622
1650
  }
1623
1651
  }
1624
1652
  function installAgentPrompts(config, workspacePath, dataPaths) {
1625
1653
  const agentCoreDir = getAgentCoreDir();
1626
1654
  syncMetadataToAll(agentCoreDir, dataPaths);
1627
- copyDirToAllStoragePaths(path11.join(agentCoreDir, "templates"), "templates", dataPaths);
1628
- copyDirToAllStoragePaths(path11.join(agentCoreDir, "prompts"), "prompts", dataPaths);
1629
- copyDirToAllStoragePaths(path11.join(agentCoreDir, "docs"), "docs", dataPaths);
1655
+ copyDirToAllStoragePaths(path12.join(agentCoreDir, "templates"), "templates", dataPaths);
1656
+ copyDirToAllStoragePaths(path12.join(agentCoreDir, "prompts"), "prompts", dataPaths);
1657
+ copyDirToAllStoragePaths(path12.join(agentCoreDir, "docs"), "docs", dataPaths);
1630
1658
  const rrceHome = config.globalPath || getDefaultRRCEHome2();
1631
- ensureDir(path11.join(rrceHome, "templates"));
1632
- ensureDir(path11.join(rrceHome, "docs"));
1633
- copyDirRecursive(path11.join(agentCoreDir, "templates"), path11.join(rrceHome, "templates"));
1634
- copyDirRecursive(path11.join(agentCoreDir, "docs"), path11.join(rrceHome, "docs"));
1659
+ ensureDir(path12.join(rrceHome, "templates"));
1660
+ ensureDir(path12.join(rrceHome, "docs"));
1661
+ copyDirRecursive(path12.join(agentCoreDir, "templates"), path12.join(rrceHome, "templates"));
1662
+ copyDirRecursive(path12.join(agentCoreDir, "docs"), path12.join(rrceHome, "docs"));
1635
1663
  const needsIDEPrompts = config.storageMode === "workspace" && (config.tools.includes("copilot") || config.tools.includes("antigravity")) || config.tools.includes("opencode");
1636
1664
  if (needsIDEPrompts) {
1637
1665
  const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
@@ -1648,12 +1676,12 @@ function installAgentPrompts(config, workspacePath, dataPaths) {
1648
1676
  }
1649
1677
  }
1650
1678
  if (config.tools.includes("opencode")) {
1651
- const opencodePath = path11.join(workspacePath, ".opencode", "agent");
1679
+ const opencodePath = path12.join(workspacePath, ".opencode", "agent");
1652
1680
  ensureDir(opencodePath);
1653
1681
  for (const prompt of prompts) {
1654
- const baseName = path11.basename(prompt.filePath, ".md");
1682
+ const baseName = path12.basename(prompt.filePath, ".md");
1655
1683
  const content = convertToOpenCodeAgent(prompt);
1656
- fs10.writeFileSync(path11.join(opencodePath, `${baseName}.md`), content);
1684
+ fs10.writeFileSync(path12.join(opencodePath, `${baseName}.md`), content);
1657
1685
  }
1658
1686
  }
1659
1687
  }
@@ -1662,11 +1690,11 @@ function createWorkspaceConfig(config, workspacePath, workspaceName) {
1662
1690
  let configPath;
1663
1691
  if (config.storageMode === "global") {
1664
1692
  const rrceHome = config.globalPath || getDefaultRRCEHome2();
1665
- configPath = path11.join(rrceHome, "workspaces", workspaceName, "config.yaml");
1693
+ configPath = path12.join(rrceHome, "workspaces", workspaceName, "config.yaml");
1666
1694
  } else {
1667
- configPath = path11.join(workspacePath, ".rrce-workflow", "config.yaml");
1695
+ configPath = path12.join(workspacePath, ".rrce-workflow", "config.yaml");
1668
1696
  }
1669
- ensureDir(path11.dirname(configPath));
1697
+ ensureDir(path12.dirname(configPath));
1670
1698
  let content = `# RRCE-Workflow Configuration
1671
1699
  version: 1
1672
1700
 
@@ -1729,8 +1757,8 @@ You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
1729
1757
  }
1730
1758
  }
1731
1759
  function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
1732
- const globalPath = path11.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
1733
- const workspacePath = path11.join(workspaceRoot, ".rrce-workflow");
1760
+ const globalPath = path12.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
1761
+ const workspacePath = path12.join(workspaceRoot, ".rrce-workflow");
1734
1762
  switch (mode) {
1735
1763
  case "global":
1736
1764
  return [globalPath];
@@ -1784,9 +1812,9 @@ __export(gitignore_exports, {
1784
1812
  updateGitignore: () => updateGitignore
1785
1813
  });
1786
1814
  import * as fs11 from "fs";
1787
- import * as path12 from "path";
1815
+ import * as path13 from "path";
1788
1816
  function updateGitignore(workspacePath, storageMode, tools) {
1789
- const gitignorePath = path12.join(workspacePath, ".gitignore");
1817
+ const gitignorePath = path13.join(workspacePath, ".gitignore");
1790
1818
  const entries = [];
1791
1819
  if (storageMode === "workspace") {
1792
1820
  entries.push(".rrce-workflow/");
@@ -1826,11 +1854,11 @@ var init_gitignore = __esm({
1826
1854
 
1827
1855
  // src/mcp/logger.ts
1828
1856
  import * as fs12 from "fs";
1829
- import * as path13 from "path";
1857
+ import * as path14 from "path";
1830
1858
  function getLogFilePath() {
1831
1859
  const workspaceRoot = detectWorkspaceRoot();
1832
1860
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1833
- return path13.join(rrceHome, "mcp-server.log");
1861
+ return path14.join(rrceHome, "mcp-server.log");
1834
1862
  }
1835
1863
  var Logger, logger;
1836
1864
  var init_logger = __esm({
@@ -1861,7 +1889,7 @@ ${JSON.stringify(data, null, 2)}`;
1861
1889
  }
1862
1890
  logMessage += "\n";
1863
1891
  try {
1864
- const dir = path13.dirname(this.logPath);
1892
+ const dir = path14.dirname(this.logPath);
1865
1893
  if (!fs12.existsSync(dir)) {
1866
1894
  fs12.mkdirSync(dir, { recursive: true });
1867
1895
  }
@@ -1890,7 +1918,7 @@ ${JSON.stringify(data, null, 2)}`;
1890
1918
 
1891
1919
  // src/mcp/services/rag.ts
1892
1920
  import * as fs13 from "fs";
1893
- import * as path14 from "path";
1921
+ import * as path15 from "path";
1894
1922
  var INDEX_VERSION, DEFAULT_MODEL, RAGService;
1895
1923
  var init_rag = __esm({
1896
1924
  "src/mcp/services/rag.ts"() {
@@ -1972,7 +2000,7 @@ var init_rag = __esm({
1972
2000
  saveIndex() {
1973
2001
  if (!this.index) return;
1974
2002
  try {
1975
- const dir = path14.dirname(this.indexPath);
2003
+ const dir = path15.dirname(this.indexPath);
1976
2004
  if (!fs13.existsSync(dir)) {
1977
2005
  fs13.mkdirSync(dir, { recursive: true });
1978
2006
  }
@@ -2138,21 +2166,19 @@ var init_rag = __esm({
2138
2166
 
2139
2167
  // src/mcp/resources.ts
2140
2168
  import * as fs14 from "fs";
2141
- import * as path15 from "path";
2169
+ import * as path16 from "path";
2142
2170
  function getExposedProjects() {
2143
2171
  const config = loadMCPConfig();
2144
2172
  const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
2145
2173
  const allProjects = projectService.scan({ knownPaths });
2146
- const globalProjects = allProjects.filter((project) => isProjectExposed(config, project.name, project.dataPath));
2147
- const activeProject = detectActiveProject(globalProjects);
2148
- let linkedProjects = [];
2174
+ const activeProject = detectActiveProject(allProjects);
2175
+ const potentialProjects = [...allProjects];
2149
2176
  if (activeProject) {
2150
- const localConfigPath = path15.join(activeProject.dataPath, "config.yaml");
2151
2177
  let cfgContent = null;
2152
- if (fs14.existsSync(path15.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
2153
- cfgContent = fs14.readFileSync(path15.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
2154
- } else if (fs14.existsSync(path15.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
2155
- cfgContent = fs14.readFileSync(path15.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
2178
+ if (fs14.existsSync(path16.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
2179
+ cfgContent = fs14.readFileSync(path16.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
2180
+ } else if (fs14.existsSync(path16.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
2181
+ cfgContent = fs14.readFileSync(path16.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
2156
2182
  }
2157
2183
  if (cfgContent) {
2158
2184
  if (cfgContent.includes("linked_projects:")) {
@@ -2172,10 +2198,10 @@ function getExposedProjects() {
2172
2198
  if (inLinked && trimmed.startsWith("-")) {
2173
2199
  const val = trimmed.replace(/^-\s*/, "").trim();
2174
2200
  const [pName] = val.split(":");
2175
- if (!globalProjects.some((p) => p.name === pName) && !linkedProjects.some((p) => p.name === pName)) {
2201
+ if (!potentialProjects.some((p) => p.name === pName)) {
2176
2202
  const found = allProjects.find((p) => p.name === pName);
2177
2203
  if (found) {
2178
- linkedProjects.push(found);
2204
+ potentialProjects.push(found);
2179
2205
  }
2180
2206
  }
2181
2207
  }
@@ -2184,11 +2210,11 @@ function getExposedProjects() {
2184
2210
  }
2185
2211
  }
2186
2212
  }
2187
- return [...globalProjects, ...linkedProjects];
2213
+ return potentialProjects.filter((project) => isProjectExposed(config, project.name, project.path));
2188
2214
  }
2189
2215
  function getRAGIndexPath(project) {
2190
2216
  const scanRoot = project.path || project.dataPath;
2191
- return path15.join(project.knowledgePath || path15.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
2217
+ return path16.join(project.knowledgePath || path16.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
2192
2218
  }
2193
2219
  function detectActiveProject(knownProjects) {
2194
2220
  let scanList = knownProjects;
@@ -2196,25 +2222,25 @@ function detectActiveProject(knownProjects) {
2196
2222
  const config = loadMCPConfig();
2197
2223
  const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
2198
2224
  const all = projectService.scan({ knownPaths });
2199
- scanList = all.filter((project) => isProjectExposed(config, project.name, project.dataPath));
2225
+ scanList = all.filter((project) => isProjectExposed(config, project.name, project.path));
2200
2226
  }
2201
2227
  return findClosestProject(scanList);
2202
2228
  }
2203
2229
  function getProjectContext(projectName) {
2204
2230
  const config = loadMCPConfig();
2205
2231
  const projects = projectService.scan();
2206
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
2232
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.path));
2207
2233
  if (!project) {
2208
2234
  return null;
2209
2235
  }
2210
- const permissions = getProjectPermissions(config, projectName, project.dataPath);
2236
+ const permissions = getProjectPermissions(config, projectName, project.path);
2211
2237
  if (!permissions.knowledge) {
2212
2238
  return null;
2213
2239
  }
2214
2240
  if (!project.knowledgePath) {
2215
2241
  return null;
2216
2242
  }
2217
- const contextPath = path15.join(project.knowledgePath, "project-context.md");
2243
+ const contextPath = path16.join(project.knowledgePath, "project-context.md");
2218
2244
  if (!fs14.existsSync(contextPath)) {
2219
2245
  return null;
2220
2246
  }
@@ -2223,11 +2249,11 @@ function getProjectContext(projectName) {
2223
2249
  function getProjectTasks(projectName) {
2224
2250
  const config = loadMCPConfig();
2225
2251
  const projects = projectService.scan();
2226
- const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.dataPath));
2252
+ const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.path));
2227
2253
  if (!project) {
2228
2254
  return [];
2229
2255
  }
2230
- const permissions = getProjectPermissions(config, projectName, project.dataPath);
2256
+ const permissions = getProjectPermissions(config, projectName, project.path);
2231
2257
  if (!permissions.tasks) {
2232
2258
  return [];
2233
2259
  }
@@ -2239,7 +2265,7 @@ function getProjectTasks(projectName) {
2239
2265
  const taskDirs = fs14.readdirSync(project.tasksPath, { withFileTypes: true });
2240
2266
  for (const dir of taskDirs) {
2241
2267
  if (!dir.isDirectory()) continue;
2242
- const metaPath = path15.join(project.tasksPath, dir.name, "meta.json");
2268
+ const metaPath = path16.join(project.tasksPath, dir.name, "meta.json");
2243
2269
  if (fs14.existsSync(metaPath)) {
2244
2270
  try {
2245
2271
  const meta = JSON.parse(fs14.readFileSync(metaPath, "utf-8"));
@@ -2259,21 +2285,21 @@ async function searchKnowledge(query, projectFilter) {
2259
2285
  const queryLower = query.toLowerCase();
2260
2286
  for (const project of projects) {
2261
2287
  if (projectFilter && project.name !== projectFilter) continue;
2262
- const permissions = getProjectPermissions(config, project.name, project.dataPath);
2288
+ const permissions = getProjectPermissions(config, project.name, project.path);
2263
2289
  if (!permissions.knowledge || !project.knowledgePath) continue;
2264
2290
  const projConfig = config.projects.find(
2265
- (p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
2291
+ (p) => p.path && normalizeProjectPath(p.path) === normalizeProjectPath(project.path) || !p.path && p.name === project.name
2266
2292
  );
2267
2293
  const useRAG = projConfig?.semanticSearch?.enabled;
2268
2294
  if (useRAG) {
2269
2295
  try {
2270
- const indexPath = path15.join(project.knowledgePath, "embeddings.json");
2296
+ const indexPath = path16.join(project.knowledgePath, "embeddings.json");
2271
2297
  const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
2272
2298
  const ragResults = await rag.search(query, 5);
2273
2299
  for (const r of ragResults) {
2274
2300
  results.push({
2275
2301
  project: project.name,
2276
- file: path15.relative(project.knowledgePath, r.filePath),
2302
+ file: path16.relative(project.knowledgePath, r.filePath),
2277
2303
  matches: [r.content],
2278
2304
  // The chunk content is the match
2279
2305
  score: r.score
@@ -2287,7 +2313,7 @@ async function searchKnowledge(query, projectFilter) {
2287
2313
  const files = fs14.readdirSync(project.knowledgePath);
2288
2314
  for (const file of files) {
2289
2315
  if (!file.endsWith(".md")) continue;
2290
- const filePath = path15.join(project.knowledgePath, file);
2316
+ const filePath = path16.join(project.knowledgePath, file);
2291
2317
  const content = fs14.readFileSync(filePath, "utf-8");
2292
2318
  const lines = content.split("\n");
2293
2319
  const matches = [];
@@ -2318,7 +2344,7 @@ async function indexKnowledge(projectName, force = false) {
2318
2344
  return { success: false, message: `Project '${projectName}' not found`, filesIndexed: 0, filesSkipped: 0 };
2319
2345
  }
2320
2346
  const projConfig = config.projects.find(
2321
- (p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
2347
+ (p) => p.path && normalizeProjectPath(p.path) === normalizeProjectPath(project.path) || !p.path && p.name === project.name
2322
2348
  ) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
2323
2349
  const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
2324
2350
  if (!isEnabled) {
@@ -2368,7 +2394,7 @@ async function indexKnowledge(projectName, force = false) {
2368
2394
  ];
2369
2395
  const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv", "target", "vendor"];
2370
2396
  try {
2371
- const indexPath = path15.join(project.knowledgePath || path15.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
2397
+ const indexPath = path16.join(project.knowledgePath || path16.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
2372
2398
  const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
2373
2399
  const rag = new RAGService(indexPath, model);
2374
2400
  let indexed = 0;
@@ -2376,14 +2402,14 @@ async function indexKnowledge(projectName, force = false) {
2376
2402
  const scanDir = async (dir) => {
2377
2403
  const entries = fs14.readdirSync(dir, { withFileTypes: true });
2378
2404
  for (const entry of entries) {
2379
- const fullPath = path15.join(dir, entry.name);
2405
+ const fullPath = path16.join(dir, entry.name);
2380
2406
  if (entry.isDirectory()) {
2381
2407
  if (SKIP_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
2382
2408
  continue;
2383
2409
  }
2384
2410
  await scanDir(fullPath);
2385
2411
  } else if (entry.isFile()) {
2386
- const ext = path15.extname(entry.name).toLowerCase();
2412
+ const ext = path16.extname(entry.name).toLowerCase();
2387
2413
  if (!INDEXABLE_EXTENSIONS.includes(ext)) {
2388
2414
  continue;
2389
2415
  }
@@ -2420,7 +2446,7 @@ function getContextPreamble() {
2420
2446
  const activeProject = detectActiveProject();
2421
2447
  let contextPreamble = "";
2422
2448
  if (activeProject) {
2423
- const rrceHome = process.env.RRCE_HOME || path15.join(__require("os").homedir(), ".rrce-workflow");
2449
+ const rrceHome = process.env.RRCE_HOME || path16.join(__require("os").homedir(), ".rrce-workflow");
2424
2450
  const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
2425
2451
  const rrceData = activeProject.dataPath;
2426
2452
  contextPreamble += `
@@ -2437,7 +2463,7 @@ Use these values directly in your operations. Do NOT manually resolve paths.
2437
2463
  `;
2438
2464
  }
2439
2465
  const projectList = projects.map((p) => {
2440
- const isActive = activeProject && p.dataPath === activeProject.dataPath;
2466
+ const isActive = activeProject && normalizeProjectPath(p.path) === normalizeProjectPath(activeProject.path);
2441
2467
  return `- ${p.name} (${p.source}) ${isActive ? "**[ACTIVE]**" : ""}`;
2442
2468
  }).join("\n");
2443
2469
  contextPreamble += `
@@ -2465,6 +2491,7 @@ var init_resources = __esm({
2465
2491
  "src/mcp/resources.ts"() {
2466
2492
  "use strict";
2467
2493
  init_config();
2494
+ init_config_utils();
2468
2495
  init_detection();
2469
2496
  init_detection_service();
2470
2497
  init_rag();
@@ -2555,7 +2582,7 @@ var init_resources2 = __esm({
2555
2582
  });
2556
2583
 
2557
2584
  // src/mcp/prompts.ts
2558
- import * as path16 from "path";
2585
+ import * as path17 from "path";
2559
2586
  function getAllPrompts() {
2560
2587
  const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
2561
2588
  return prompts.map((p) => {
@@ -2608,8 +2635,8 @@ function renderPromptWithContext(content, args) {
2608
2635
  resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
2609
2636
  resolvedWorkspaceName = activeProject.name;
2610
2637
  if (activeProject.source === "global") {
2611
- const workspacesDir = path16.dirname(activeProject.dataPath);
2612
- resolvedRrceHome = path16.dirname(workspacesDir);
2638
+ const workspacesDir = path17.dirname(activeProject.dataPath);
2639
+ resolvedRrceHome = path17.dirname(workspacesDir);
2613
2640
  }
2614
2641
  }
2615
2642
  if (!renderArgs["RRCE_DATA"]) renderArgs["RRCE_DATA"] = resolvedRrceData;
@@ -3059,7 +3086,7 @@ Hidden projects: ${projects.length - exposedCount}`,
3059
3086
  async function handleConfigureGlobalPath() {
3060
3087
  const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
3061
3088
  const fs21 = await import("fs");
3062
- const path20 = await import("path");
3089
+ const path21 = await import("path");
3063
3090
  note3(
3064
3091
  `MCP Hub requires a ${pc5.bold("global storage path")} to store its configuration
3065
3092
  and coordinate across projects.
@@ -3082,7 +3109,7 @@ locally in each project. MCP needs a central location.`,
3082
3109
  `${pc5.green("\u2713")} Global path configured: ${pc5.cyan(resolvedPath)}
3083
3110
 
3084
3111
  MCP config will be stored at:
3085
- ${path20.join(resolvedPath, "mcp.yaml")}`,
3112
+ ${path21.join(resolvedPath, "mcp.yaml")}`,
3086
3113
  "Configuration Saved"
3087
3114
  );
3088
3115
  return true;
@@ -3324,7 +3351,7 @@ var init_SimpleSelect = __esm({
3324
3351
 
3325
3352
  // src/mcp/ui/ProjectsView.tsx
3326
3353
  import { useState as useState2 } from "react";
3327
- import { Box as Box4, Text as Text4 } from "ink";
3354
+ import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
3328
3355
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
3329
3356
  var ProjectsView;
3330
3357
  var init_ProjectsView = __esm({
@@ -3334,6 +3361,20 @@ var init_ProjectsView = __esm({
3334
3361
  init_config();
3335
3362
  ProjectsView = ({ config: initialConfig, projects: allProjects, onConfigChange }) => {
3336
3363
  const [config, setConfig] = useState2(initialConfig);
3364
+ useInput2((input) => {
3365
+ if (input === "a") {
3366
+ const newConfig = {
3367
+ ...config,
3368
+ defaults: {
3369
+ ...config.defaults,
3370
+ includeNew: !config.defaults.includeNew
3371
+ }
3372
+ };
3373
+ saveMCPConfig(newConfig);
3374
+ setConfig(newConfig);
3375
+ if (onConfigChange) onConfigChange();
3376
+ }
3377
+ });
3337
3378
  const projectItems = allProjects.map((p) => {
3338
3379
  const projectConfig = config.projects.find(
3339
3380
  (c) => c.path && c.path === p.path || p.source === "global" && c.name === p.name || !c.path && c.name === p.name
@@ -3341,9 +3382,9 @@ var init_ProjectsView = __esm({
3341
3382
  const isExposed = projectConfig ? projectConfig.expose : config.defaults.includeNew;
3342
3383
  return {
3343
3384
  label: p.name + ` (${p.source})` + (p.path ? ` - ${p.path}` : ""),
3344
- value: p.dataPath,
3345
- // Unique ID
3346
- key: p.dataPath,
3385
+ value: p.path,
3386
+ // Standardized ID: Use root path
3387
+ key: p.path,
3347
3388
  exposed: isExposed
3348
3389
  };
3349
3390
  });
@@ -3352,7 +3393,7 @@ var init_ProjectsView = __esm({
3352
3393
  let newConfig = { ...config };
3353
3394
  projectItems.forEach((item) => {
3354
3395
  const isSelected = selectedIds.includes(item.value);
3355
- const project = allProjects.find((p) => p.dataPath === item.value);
3396
+ const project = allProjects.find((p) => p.path === item.value);
3356
3397
  if (project) {
3357
3398
  const existingConfig = newConfig.projects.find((p) => p.name === project.name);
3358
3399
  const projectPath = project.source === "global" && existingConfig?.path ? existingConfig.path : project.path;
@@ -3370,7 +3411,14 @@ var init_ProjectsView = __esm({
3370
3411
  if (onConfigChange) onConfigChange();
3371
3412
  };
3372
3413
  return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan", flexGrow: 1, children: [
3373
- /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: " Exposed Projects " }),
3414
+ /* @__PURE__ */ jsxs3(Box4, { justifyContent: "space-between", children: [
3415
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: " Exposed Projects " }),
3416
+ /* @__PURE__ */ jsxs3(Box4, { children: [
3417
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Auto-expose new: " }),
3418
+ /* @__PURE__ */ jsx4(Text4, { color: config.defaults.includeNew ? "green" : "red", children: config.defaults.includeNew ? "ON" : "OFF" }),
3419
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " (Press 'a' to toggle)" })
3420
+ ] })
3421
+ ] }),
3374
3422
  /* @__PURE__ */ jsx4(Text4, { color: "dim", children: " Select projects to expose via the MCP server. Use Space to toggle, Enter to save." }),
3375
3423
  /* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx4(
3376
3424
  SimpleSelect,
@@ -3385,7 +3433,7 @@ var init_ProjectsView = __esm({
3385
3433
  onCancel: () => {
3386
3434
  }
3387
3435
  },
3388
- JSON.stringify(initialSelected)
3436
+ JSON.stringify(initialSelected) + config.defaults.includeNew
3389
3437
  ) })
3390
3438
  ] });
3391
3439
  };
@@ -3651,14 +3699,14 @@ var init_IndexingStatus = __esm({
3651
3699
 
3652
3700
  // src/mcp/ui/components/TabBar.tsx
3653
3701
  import "react";
3654
- import { Box as Box10, Text as Text10, useInput as useInput2 } from "ink";
3702
+ import { Box as Box10, Text as Text10, useInput as useInput3 } from "ink";
3655
3703
  import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
3656
3704
  var TabBar;
3657
3705
  var init_TabBar = __esm({
3658
3706
  "src/mcp/ui/components/TabBar.tsx"() {
3659
3707
  "use strict";
3660
3708
  TabBar = ({ tabs, activeTab, onChange }) => {
3661
- useInput2((input, key) => {
3709
+ useInput3((input, key) => {
3662
3710
  if (key.leftArrow) {
3663
3711
  const index = tabs.findIndex((t) => t.id === activeTab);
3664
3712
  if (index !== -1) {
@@ -3705,7 +3753,7 @@ __export(App_exports, {
3705
3753
  App: () => App
3706
3754
  });
3707
3755
  import { useState as useState5, useEffect as useEffect4, useMemo as useMemo2, useCallback } from "react";
3708
- import { Box as Box11, useInput as useInput3, useApp } from "ink";
3756
+ import { Box as Box11, useInput as useInput4, useApp } from "ink";
3709
3757
  import fs15 from "fs";
3710
3758
  import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
3711
3759
  var App;
@@ -3724,6 +3772,7 @@ var init_App = __esm({
3724
3772
  init_detection();
3725
3773
  init_logger();
3726
3774
  init_server();
3775
+ init_resources();
3727
3776
  init_install();
3728
3777
  init_paths();
3729
3778
  App = ({ onExit, initialPort }) => {
@@ -3742,12 +3791,7 @@ var init_App = __esm({
3742
3791
  setProjects(scanForProjects());
3743
3792
  }, []);
3744
3793
  const exposedProjects = useMemo2(
3745
- () => projects.filter((p) => {
3746
- const cfg = config.projects.find(
3747
- (c) => c.path && c.path === p.path || p.source === "global" && c.name === p.name || !c.path && c.name === p.name
3748
- );
3749
- return cfg?.expose ?? config.defaults.includeNew;
3750
- }),
3794
+ () => projects.filter((p) => isProjectExposed(config, p.name, p.path)),
3751
3795
  [projects, config]
3752
3796
  );
3753
3797
  const isRAGEnabled = useMemo2(() => {
@@ -3819,7 +3863,7 @@ var init_App = __esm({
3819
3863
  }, 500);
3820
3864
  return () => clearInterval(interval);
3821
3865
  }, []);
3822
- useInput3(async (input, key) => {
3866
+ useInput4(async (input, key) => {
3823
3867
  if (input === "q" || key.ctrl && input === "c") {
3824
3868
  stopMCPServer();
3825
3869
  onExit();
@@ -4562,14 +4606,14 @@ var init_link_flow = __esm({
4562
4606
  import { confirm as confirm8, spinner as spinner5, note as note11, outro as outro4, cancel as cancel5, isCancel as isCancel10 } from "@clack/prompts";
4563
4607
  import pc13 from "picocolors";
4564
4608
  import * as fs17 from "fs";
4565
- import * as path17 from "path";
4609
+ import * as path18 from "path";
4566
4610
  async function runSyncToGlobalFlow(workspacePath, workspaceName) {
4567
4611
  const localPath = getLocalWorkspacePath(workspacePath);
4568
4612
  const customGlobalPath = getEffectiveRRCEHome(workspacePath);
4569
- const globalPath = path17.join(customGlobalPath, "workspaces", workspaceName);
4613
+ const globalPath = path18.join(customGlobalPath, "workspaces", workspaceName);
4570
4614
  const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
4571
4615
  const existingDirs = subdirs.filter(
4572
- (dir) => fs17.existsSync(path17.join(localPath, dir))
4616
+ (dir) => fs17.existsSync(path18.join(localPath, dir))
4573
4617
  );
4574
4618
  if (existingDirs.length === 0) {
4575
4619
  outro4(pc13.yellow("No data found in workspace storage to sync."));
@@ -4595,8 +4639,8 @@ Destination: ${pc13.cyan(globalPath)}`,
4595
4639
  try {
4596
4640
  ensureDir(globalPath);
4597
4641
  for (const dir of existingDirs) {
4598
- const srcDir = path17.join(localPath, dir);
4599
- const destDir = path17.join(globalPath, dir);
4642
+ const srcDir = path18.join(localPath, dir);
4643
+ const destDir = path18.join(globalPath, dir);
4600
4644
  ensureDir(destDir);
4601
4645
  copyDirRecursive(srcDir, destDir);
4602
4646
  }
@@ -4629,7 +4673,7 @@ var init_sync_flow = __esm({
4629
4673
  import { confirm as confirm9, spinner as spinner6, note as note12, outro as outro5, cancel as cancel6, isCancel as isCancel11 } from "@clack/prompts";
4630
4674
  import pc14 from "picocolors";
4631
4675
  import * as fs18 from "fs";
4632
- import * as path18 from "path";
4676
+ import * as path19 from "path";
4633
4677
  async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
4634
4678
  const s = spinner6();
4635
4679
  s.start("Checking for updates");
@@ -4659,7 +4703,7 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
4659
4703
  }
4660
4704
  s.start("Updating from package");
4661
4705
  for (const dataPath of dataPaths) {
4662
- copyDirToAllStoragePaths(path18.join(agentCoreDir, "templates"), "templates", [dataPath]);
4706
+ copyDirToAllStoragePaths(path19.join(agentCoreDir, "templates"), "templates", [dataPath]);
4663
4707
  }
4664
4708
  const configFilePath = getConfigPath(workspacePath);
4665
4709
  if (fs18.existsSync(configFilePath)) {
@@ -4692,8 +4736,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
4692
4736
  }
4693
4737
  }
4694
4738
  function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
4695
- const globalPath = path18.join(customGlobalPath, "workspaces", workspaceName);
4696
- const workspacePath = path18.join(workspaceRoot, ".rrce-workflow");
4739
+ const globalPath = path19.join(customGlobalPath, "workspaces", workspaceName);
4740
+ const workspacePath = path19.join(workspaceRoot, ".rrce-workflow");
4697
4741
  switch (mode) {
4698
4742
  case "global":
4699
4743
  return [globalPath];
@@ -4925,9 +4969,9 @@ init_wizard();
4925
4969
  init_prompts();
4926
4970
  import { intro as intro3, select as select6, note as note15, cancel as cancel9, isCancel as isCancel14, outro as outro8 } from "@clack/prompts";
4927
4971
  import pc17 from "picocolors";
4928
- import * as path19 from "path";
4972
+ import * as path20 from "path";
4929
4973
  async function runSelector() {
4930
- const workspaceName = path19.basename(process.cwd());
4974
+ const workspaceName = path20.basename(process.cwd());
4931
4975
  intro3(pc17.cyan(pc17.inverse(` RRCE-Workflow | ${workspaceName} `)));
4932
4976
  const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
4933
4977
  if (prompts.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rrce-workflow",
3
- "version": "0.2.72",
3
+ "version": "0.2.73",
4
4
  "description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
5
5
  "author": "RRCE Team",
6
6
  "license": "MIT",