rrce-workflow 0.3.20 → 0.3.23

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
@@ -1028,19 +1028,60 @@ var init_install = __esm({
1028
1028
  }
1029
1029
  });
1030
1030
 
1031
- // src/commands/wizard/utils.ts
1031
+ // src/commands/wizard/fs-utils.ts
1032
1032
  import * as fs7 from "fs";
1033
1033
  import * as path8 from "path";
1034
+ function copyDirRecursive(src, dest) {
1035
+ const entries = fs7.readdirSync(src, { withFileTypes: true });
1036
+ for (const entry of entries) {
1037
+ const srcPath = path8.join(src, entry.name);
1038
+ const destPath = path8.join(dest, entry.name);
1039
+ if (entry.isDirectory()) {
1040
+ ensureDir(destPath);
1041
+ copyDirRecursive(srcPath, destPath);
1042
+ } else {
1043
+ fs7.copyFileSync(srcPath, destPath);
1044
+ }
1045
+ }
1046
+ }
1047
+ function clearDirectory(dirPath) {
1048
+ if (!fs7.existsSync(dirPath)) return;
1049
+ const entries = fs7.readdirSync(dirPath, { withFileTypes: true });
1050
+ for (const entry of entries) {
1051
+ if (entry.isFile()) {
1052
+ fs7.unlinkSync(path8.join(dirPath, entry.name));
1053
+ }
1054
+ }
1055
+ }
1056
+ function copyPromptsToDir(prompts, targetDir, extension) {
1057
+ for (const prompt of prompts) {
1058
+ const baseName = path8.basename(prompt.filePath, ".md");
1059
+ const targetName = baseName + extension;
1060
+ const targetPath = path8.join(targetDir, targetName);
1061
+ const content = fs7.readFileSync(prompt.filePath, "utf-8");
1062
+ fs7.writeFileSync(targetPath, content);
1063
+ }
1064
+ }
1065
+ var init_fs_utils = __esm({
1066
+ "src/commands/wizard/fs-utils.ts"() {
1067
+ "use strict";
1068
+ init_paths();
1069
+ }
1070
+ });
1071
+
1072
+ // src/commands/wizard/opencode-service.ts
1073
+ import * as fs8 from "fs";
1074
+ import * as path9 from "path";
1034
1075
  import * as os2 from "os";
1035
1076
  import { stringify } from "yaml";
1036
1077
  function getOpenCodeConfigPath() {
1037
- return path8.join(os2.homedir(), ".config", "opencode", "opencode.json");
1078
+ return path9.join(os2.homedir(), ".config", "opencode", "opencode.json");
1038
1079
  }
1039
1080
  function getOpenCodeCommandDir(mode, dataPath) {
1040
1081
  if (mode === "global") {
1041
- return path8.join(os2.homedir(), ".config", "opencode", "command");
1082
+ return path9.join(os2.homedir(), ".config", "opencode", "command");
1042
1083
  }
1043
- return path8.join(dataPath, ".opencode", "command");
1084
+ return path9.join(dataPath, ".opencode", "command");
1044
1085
  }
1045
1086
  function mapPromptToCommandName(baseName) {
1046
1087
  const mapping = {
@@ -1054,9 +1095,9 @@ function mapPromptToCommandName(baseName) {
1054
1095
  return mapping[baseName] || baseName;
1055
1096
  }
1056
1097
  function loadBaseProtocol() {
1057
- const basePath = path8.join(getAgentCorePromptsDir(), "_base.md");
1058
- if (fs7.existsSync(basePath)) {
1059
- return fs7.readFileSync(basePath, "utf-8");
1098
+ const basePath = path9.join(getAgentCorePromptsDir(), "_base.md");
1099
+ if (fs8.existsSync(basePath)) {
1100
+ return fs8.readFileSync(basePath, "utf-8");
1060
1101
  }
1061
1102
  return "";
1062
1103
  }
@@ -1073,18 +1114,18 @@ function buildCommandFrontmatter(prompt, baseName) {
1073
1114
  function generateOpenCodeCommands(prompts, mode, dataPath) {
1074
1115
  const commandDir = getOpenCodeCommandDir(mode, dataPath);
1075
1116
  ensureDir(commandDir);
1076
- if (fs7.existsSync(commandDir)) {
1077
- const entries = fs7.readdirSync(commandDir, { withFileTypes: true });
1117
+ if (fs8.existsSync(commandDir)) {
1118
+ const entries = fs8.readdirSync(commandDir, { withFileTypes: true });
1078
1119
  for (const entry of entries) {
1079
1120
  const fileName = entry.name;
1080
1121
  if (entry.isFile() && fileName.startsWith("rrce_") && fileName.endsWith(".md")) {
1081
- fs7.unlinkSync(path8.join(commandDir, fileName));
1122
+ fs8.unlinkSync(path9.join(commandDir, fileName));
1082
1123
  }
1083
1124
  }
1084
1125
  }
1085
1126
  const baseProtocol = loadBaseProtocol();
1086
1127
  for (const prompt of prompts) {
1087
- const baseName = path8.basename(prompt.filePath, ".md");
1128
+ const baseName = path9.basename(prompt.filePath, ".md");
1088
1129
  if (baseName === "orchestrator") continue;
1089
1130
  if (baseName.startsWith("_")) continue;
1090
1131
  const commandName = mapPromptToCommandName(baseName);
@@ -1095,52 +1136,16 @@ ${prompt.content}` : prompt.content;
1095
1136
  const content = `---
1096
1137
  ${stringify(frontmatter)}---
1097
1138
  ${fullContent}`;
1098
- fs7.writeFileSync(path8.join(commandDir, commandFile), content);
1099
- }
1100
- }
1101
- function enableProviderCaching() {
1102
- const opencodePath = getOpenCodeConfigPath();
1103
- let config = {};
1104
- if (fs7.existsSync(opencodePath)) {
1105
- try {
1106
- config = JSON.parse(fs7.readFileSync(opencodePath, "utf8"));
1107
- } catch (e) {
1108
- console.error("Warning: Could not parse existing OpenCode config, creating new provider section");
1109
- }
1110
- } else {
1111
- ensureDir(path8.dirname(opencodePath));
1112
- }
1113
- if (!config.provider) {
1114
- config.provider = {};
1115
- }
1116
- const providers = ["anthropic", "openai", "openrouter", "google"];
1117
- for (const provider of providers) {
1118
- if (!config.provider[provider]) {
1119
- config.provider[provider] = {};
1120
- }
1121
- if (!config.provider[provider].options) {
1122
- config.provider[provider].options = {};
1123
- }
1124
- config.provider[provider].options.setCacheKey = true;
1125
- }
1126
- fs7.writeFileSync(opencodePath, JSON.stringify(config, null, 2));
1127
- }
1128
- function copyPromptsToDir(prompts, targetDir, extension) {
1129
- for (const prompt of prompts) {
1130
- const baseName = path8.basename(prompt.filePath, ".md");
1131
- const targetName = baseName + extension;
1132
- const targetPath = path8.join(targetDir, targetName);
1133
- const content = fs7.readFileSync(prompt.filePath, "utf-8");
1134
- fs7.writeFileSync(targetPath, content);
1139
+ fs8.writeFileSync(path9.join(commandDir, commandFile), content);
1135
1140
  }
1136
1141
  }
1137
1142
  function updateOpenCodeConfig(newAgents) {
1138
1143
  const opencodePath = getOpenCodeConfigPath();
1139
- if (!fs7.existsSync(opencodePath)) {
1144
+ if (!fs8.existsSync(opencodePath)) {
1140
1145
  return;
1141
1146
  }
1142
1147
  try {
1143
- const config = JSON.parse(fs7.readFileSync(opencodePath, "utf8"));
1148
+ const config = JSON.parse(fs8.readFileSync(opencodePath, "utf8"));
1144
1149
  const agentConfig = config.agent ?? config.agents ?? {};
1145
1150
  const existingAgentKeys = Object.keys(agentConfig);
1146
1151
  const rrceKeys = existingAgentKeys.filter((key) => key.startsWith("rrce_"));
@@ -1156,7 +1161,7 @@ function updateOpenCodeConfig(newAgents) {
1156
1161
  }
1157
1162
  config.agent = agentConfig;
1158
1163
  if (config.agents) delete config.agents;
1159
- fs7.writeFileSync(opencodePath, JSON.stringify(config, null, 2));
1164
+ fs8.writeFileSync(opencodePath, JSON.stringify(config, null, 2));
1160
1165
  } catch (e) {
1161
1166
  console.error("Failed to update OpenCode config:", e);
1162
1167
  }
@@ -1164,7 +1169,6 @@ function updateOpenCodeConfig(newAgents) {
1164
1169
  function convertToOpenCodeAgent(prompt, useFileReference = false, promptFilePath) {
1165
1170
  const { frontmatter, content } = prompt;
1166
1171
  const tools = {};
1167
- const hostTools = ["read", "write", "edit", "bash", "grep", "glob", "webfetch", "terminalLastCommand", "task"];
1168
1172
  if (frontmatter.tools) {
1169
1173
  for (const tool of frontmatter.tools) {
1170
1174
  tools[tool] = true;
@@ -1180,48 +1184,26 @@ function convertToOpenCodeAgent(prompt, useFileReference = false, promptFilePath
1180
1184
  tools
1181
1185
  };
1182
1186
  }
1183
- function copyDirRecursive(src, dest) {
1184
- const entries = fs7.readdirSync(src, { withFileTypes: true });
1185
- for (const entry of entries) {
1186
- const srcPath = path8.join(src, entry.name);
1187
- const destPath = path8.join(dest, entry.name);
1188
- if (entry.isDirectory()) {
1189
- ensureDir(destPath);
1190
- copyDirRecursive(srcPath, destPath);
1191
- } else {
1192
- fs7.copyFileSync(srcPath, destPath);
1193
- }
1194
- }
1195
- }
1196
- function clearDirectory(dirPath) {
1197
- if (!fs7.existsSync(dirPath)) return;
1198
- const entries = fs7.readdirSync(dirPath, { withFileTypes: true });
1199
- for (const entry of entries) {
1200
- if (entry.isFile()) {
1201
- fs7.unlinkSync(path8.join(dirPath, entry.name));
1202
- }
1203
- }
1204
- }
1205
1187
  function surgicalUpdateOpenCodeAgents(prompts, mode, dataPath) {
1206
1188
  const agentPrompts = prompts.filter((p) => {
1207
- const baseName = path8.basename(p.filePath, ".md");
1189
+ const baseName = path9.basename(p.filePath, ".md");
1208
1190
  return baseName === "orchestrator" || baseName === "develop";
1209
1191
  });
1210
1192
  if (mode === "global") {
1211
1193
  try {
1212
- const openCodeConfig = getOpenCodeConfigPath();
1213
- const promptsDir = path8.join(path8.dirname(openCodeConfig), "prompts");
1194
+ const openCodeConfigPath = getOpenCodeConfigPath();
1195
+ const promptsDir = path9.join(path9.dirname(openCodeConfigPath), "prompts");
1214
1196
  ensureDir(promptsDir);
1215
1197
  const baseProtocol = loadBaseProtocol();
1216
1198
  const newAgents = {};
1217
1199
  for (const prompt of agentPrompts) {
1218
- const baseName = path8.basename(prompt.filePath, ".md");
1200
+ const baseName = path9.basename(prompt.filePath, ".md");
1219
1201
  const agentId = `rrce_${baseName}`;
1220
1202
  const promptFileName = `rrce-${baseName}.md`;
1221
- const promptFilePath = path8.join(promptsDir, promptFileName);
1203
+ const promptFilePath = path9.join(promptsDir, promptFileName);
1222
1204
  const fullContent = baseProtocol ? `${baseProtocol}
1223
1205
  ${prompt.content}` : prompt.content;
1224
- fs7.writeFileSync(promptFilePath, fullContent);
1206
+ fs8.writeFileSync(promptFilePath, fullContent);
1225
1207
  const agentConfig = convertToOpenCodeAgent(prompt, true, `./prompts/${promptFileName}`);
1226
1208
  if (baseName === "develop") {
1227
1209
  agentConfig.description = "Develop planned tasks - use /rrce_develop (in-context) or @rrce_develop (isolated)";
@@ -1229,24 +1211,22 @@ ${prompt.content}` : prompt.content;
1229
1211
  newAgents[agentId] = agentConfig;
1230
1212
  }
1231
1213
  updateOpenCodeConfig(newAgents);
1232
- if (fs7.existsSync(openCodeConfig)) {
1233
- const config = JSON.parse(fs7.readFileSync(openCodeConfig, "utf8"));
1214
+ if (fs8.existsSync(openCodeConfigPath)) {
1215
+ const config = JSON.parse(fs8.readFileSync(openCodeConfigPath, "utf8"));
1234
1216
  if (!config.agent) config.agent = {};
1235
- if (!config.agent.plan) config.agent.plan = {};
1236
- config.agent.plan.disable = true;
1237
- fs7.writeFileSync(openCodeConfig, JSON.stringify(config, null, 2));
1217
+ fs8.writeFileSync(openCodeConfigPath, JSON.stringify(config, null, 2));
1238
1218
  }
1239
1219
  } catch (e) {
1240
1220
  console.error("Failed to update global OpenCode config with agents:", e);
1241
1221
  throw e;
1242
1222
  }
1243
1223
  } else {
1244
- const opencodeBaseDir = path8.join(dataPath, ".opencode", "agent");
1224
+ const opencodeBaseDir = path9.join(dataPath, ".opencode", "agent");
1245
1225
  ensureDir(opencodeBaseDir);
1246
1226
  clearDirectory(opencodeBaseDir);
1247
1227
  const baseProtocol = loadBaseProtocol();
1248
1228
  for (const prompt of agentPrompts) {
1249
- const baseName = path8.basename(prompt.filePath, ".md");
1229
+ const baseName = path9.basename(prompt.filePath, ".md");
1250
1230
  const agentId = `rrce_${baseName}`;
1251
1231
  const agentConfig = convertToOpenCodeAgent(prompt);
1252
1232
  if (baseName === "develop") {
@@ -1261,16 +1241,53 @@ ${stringify({
1261
1241
  tools: agentConfig.tools
1262
1242
  })}---
1263
1243
  ${fullContent}`;
1264
- fs7.writeFileSync(path8.join(opencodeBaseDir, `${agentId}.md`), content);
1244
+ fs8.writeFileSync(path9.join(opencodeBaseDir, `${agentId}.md`), content);
1265
1245
  }
1266
1246
  }
1267
1247
  generateOpenCodeCommands(prompts, mode, dataPath);
1268
1248
  }
1269
- var init_utils = __esm({
1270
- "src/commands/wizard/utils.ts"() {
1249
+ function enableProviderCaching() {
1250
+ const opencodePath = getOpenCodeConfigPath();
1251
+ let config = {};
1252
+ if (fs8.existsSync(opencodePath)) {
1253
+ try {
1254
+ config = JSON.parse(fs8.readFileSync(opencodePath, "utf8"));
1255
+ } catch (e) {
1256
+ console.error("Warning: Could not parse existing OpenCode config, creating new provider section");
1257
+ }
1258
+ } else {
1259
+ ensureDir(path9.dirname(opencodePath));
1260
+ }
1261
+ if (!config.provider) {
1262
+ config.provider = {};
1263
+ }
1264
+ const providers = ["anthropic", "openai", "openrouter", "google"];
1265
+ for (const provider of providers) {
1266
+ if (!config.provider[provider]) {
1267
+ config.provider[provider] = {};
1268
+ }
1269
+ if (!config.provider[provider].options) {
1270
+ config.provider[provider].options = {};
1271
+ }
1272
+ config.provider[provider].options.setCacheKey = true;
1273
+ }
1274
+ fs8.writeFileSync(opencodePath, JSON.stringify(config, null, 2));
1275
+ }
1276
+ var init_opencode_service = __esm({
1277
+ "src/commands/wizard/opencode-service.ts"() {
1271
1278
  "use strict";
1272
1279
  init_paths();
1273
1280
  init_prompts();
1281
+ init_fs_utils();
1282
+ }
1283
+ });
1284
+
1285
+ // src/commands/wizard/utils.ts
1286
+ var init_utils = __esm({
1287
+ "src/commands/wizard/utils.ts"() {
1288
+ "use strict";
1289
+ init_fs_utils();
1290
+ init_opencode_service();
1274
1291
  }
1275
1292
  });
1276
1293
 
@@ -1303,14 +1320,14 @@ var init_types = __esm({
1303
1320
  });
1304
1321
 
1305
1322
  // src/mcp/config-utils.ts
1306
- import * as path10 from "path";
1323
+ import * as path11 from "path";
1307
1324
  function normalizeProjectPath(projectPath) {
1308
1325
  let normalized = projectPath;
1309
1326
  while (normalized.length > 1 && (normalized.endsWith("/") || normalized.endsWith("\\"))) {
1310
1327
  normalized = normalized.slice(0, -1);
1311
1328
  }
1312
1329
  if (normalized.endsWith(".rrce-workflow")) {
1313
- return path10.dirname(normalized);
1330
+ return path11.dirname(normalized);
1314
1331
  }
1315
1332
  return normalized;
1316
1333
  }
@@ -1349,8 +1366,8 @@ __export(config_exports, {
1349
1366
  saveMCPConfig: () => saveMCPConfig,
1350
1367
  setProjectConfig: () => setProjectConfig
1351
1368
  });
1352
- import * as fs9 from "fs";
1353
- import * as path11 from "path";
1369
+ import * as fs10 from "fs";
1370
+ import * as path12 from "path";
1354
1371
  import YAML from "yaml";
1355
1372
  function migrateConfig(config) {
1356
1373
  let changed = false;
@@ -1369,15 +1386,15 @@ function migrateConfig(config) {
1369
1386
  function getMCPConfigPath() {
1370
1387
  const workspaceRoot = detectWorkspaceRoot();
1371
1388
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1372
- return path11.join(rrceHome, "mcp.yaml");
1389
+ return path12.join(rrceHome, "mcp.yaml");
1373
1390
  }
1374
1391
  function loadMCPConfig() {
1375
1392
  const configPath = getMCPConfigPath();
1376
- if (!fs9.existsSync(configPath)) {
1393
+ if (!fs10.existsSync(configPath)) {
1377
1394
  return { ...DEFAULT_MCP_CONFIG };
1378
1395
  }
1379
1396
  try {
1380
- const content = fs9.readFileSync(configPath, "utf-8");
1397
+ const content = fs10.readFileSync(configPath, "utf-8");
1381
1398
  let config = parseMCPConfig(content);
1382
1399
  config = migrateConfig(config);
1383
1400
  return config;
@@ -1389,9 +1406,9 @@ function ensureMCPGlobalPath() {
1389
1406
  const workspaceRoot = detectWorkspaceRoot();
1390
1407
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1391
1408
  if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
1392
- const configPath = path11.join(workspaceRoot, ".rrce-workflow", "config.yaml");
1393
- if (fs9.existsSync(configPath)) {
1394
- const content = fs9.readFileSync(configPath, "utf-8");
1409
+ const configPath = path12.join(workspaceRoot, ".rrce-workflow", "config.yaml");
1410
+ if (fs10.existsSync(configPath)) {
1411
+ const content = fs10.readFileSync(configPath, "utf-8");
1395
1412
  const modeMatch = content.match(/mode:\s*(global|workspace)/);
1396
1413
  if (modeMatch?.[1] === "workspace") {
1397
1414
  return {
@@ -1409,12 +1426,12 @@ function ensureMCPGlobalPath() {
1409
1426
  }
1410
1427
  function saveMCPConfig(config) {
1411
1428
  const configPath = getMCPConfigPath();
1412
- const dir = path11.dirname(configPath);
1413
- if (!fs9.existsSync(dir)) {
1414
- fs9.mkdirSync(dir, { recursive: true });
1429
+ const dir = path12.dirname(configPath);
1430
+ if (!fs10.existsSync(dir)) {
1431
+ fs10.mkdirSync(dir, { recursive: true });
1415
1432
  }
1416
1433
  const content = serializeMCPConfig(config);
1417
- fs9.writeFileSync(configPath, content);
1434
+ fs10.writeFileSync(configPath, content);
1418
1435
  }
1419
1436
  function parseMCPConfig(content) {
1420
1437
  try {
@@ -1503,16 +1520,16 @@ function getProjectPermissions(config, name, projectPath) {
1503
1520
  }
1504
1521
  function cleanStaleProjects(config) {
1505
1522
  const rrceHome = getEffectiveGlobalPath();
1506
- const globalWorkspacesDir = path11.join(rrceHome, "workspaces");
1523
+ const globalWorkspacesDir = path12.join(rrceHome, "workspaces");
1507
1524
  const validProjects = [];
1508
1525
  const removed = [];
1509
1526
  for (const project of config.projects) {
1510
1527
  let exists = false;
1511
1528
  if (project.path) {
1512
- exists = fs9.existsSync(project.path);
1529
+ exists = fs10.existsSync(project.path);
1513
1530
  } else {
1514
- const globalPath = path11.join(globalWorkspacesDir, project.name);
1515
- exists = fs9.existsSync(globalPath);
1531
+ const globalPath = path12.join(globalWorkspacesDir, project.name);
1532
+ exists = fs10.existsSync(globalPath);
1516
1533
  }
1517
1534
  if (exists) {
1518
1535
  validProjects.push(project);
@@ -1539,10 +1556,10 @@ var gitignore_exports = {};
1539
1556
  __export(gitignore_exports, {
1540
1557
  updateGitignore: () => updateGitignore
1541
1558
  });
1542
- import * as fs11 from "fs";
1543
- import * as path13 from "path";
1559
+ import * as fs12 from "fs";
1560
+ import * as path14 from "path";
1544
1561
  function updateGitignore(workspacePath, storageMode, tools) {
1545
- const gitignorePath = path13.join(workspacePath, ".gitignore");
1562
+ const gitignorePath = path14.join(workspacePath, ".gitignore");
1546
1563
  const entries = [];
1547
1564
  if (storageMode === "workspace") {
1548
1565
  entries.push(".rrce-workflow/");
@@ -1561,8 +1578,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
1561
1578
  return false;
1562
1579
  }
1563
1580
  let existingContent = "";
1564
- if (fs11.existsSync(gitignorePath)) {
1565
- existingContent = fs11.readFileSync(gitignorePath, "utf-8");
1581
+ if (fs12.existsSync(gitignorePath)) {
1582
+ existingContent = fs12.readFileSync(gitignorePath, "utf-8");
1566
1583
  }
1567
1584
  const sectionMarker = "# RRCE-Workflow Generated";
1568
1585
  if (existingContent.includes(sectionMarker)) {
@@ -1573,7 +1590,7 @@ ${sectionMarker}
1573
1590
  ${entries.join("\n")}
1574
1591
  `;
1575
1592
  const updatedContent = existingContent.trimEnd() + newSection;
1576
- fs11.writeFileSync(gitignorePath, updatedContent);
1593
+ fs12.writeFileSync(gitignorePath, updatedContent);
1577
1594
  return true;
1578
1595
  }
1579
1596
  var init_gitignore = __esm({
@@ -1583,12 +1600,12 @@ var init_gitignore = __esm({
1583
1600
  });
1584
1601
 
1585
1602
  // src/mcp/logger.ts
1586
- import * as fs12 from "fs";
1587
- import * as path14 from "path";
1603
+ import * as fs13 from "fs";
1604
+ import * as path15 from "path";
1588
1605
  function getLogFilePath() {
1589
1606
  const workspaceRoot = detectWorkspaceRoot();
1590
1607
  const rrceHome = getEffectiveRRCEHome(workspaceRoot);
1591
- return path14.join(rrceHome, "mcp-server.log");
1608
+ return path15.join(rrceHome, "mcp-server.log");
1592
1609
  }
1593
1610
  var Logger, logger;
1594
1611
  var init_logger = __esm({
@@ -1619,11 +1636,11 @@ ${JSON.stringify(data, null, 2)}`;
1619
1636
  }
1620
1637
  logMessage += "\n";
1621
1638
  try {
1622
- const dir = path14.dirname(this.logPath);
1623
- if (!fs12.existsSync(dir)) {
1624
- fs12.mkdirSync(dir, { recursive: true });
1639
+ const dir = path15.dirname(this.logPath);
1640
+ if (!fs13.existsSync(dir)) {
1641
+ fs13.mkdirSync(dir, { recursive: true });
1625
1642
  }
1626
- fs12.appendFileSync(this.logPath, logMessage);
1643
+ fs13.appendFileSync(this.logPath, logMessage);
1627
1644
  } catch (e) {
1628
1645
  console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
1629
1646
  console.error(logMessage);
@@ -1739,18 +1756,18 @@ var init_constants = __esm({
1739
1756
  });
1740
1757
 
1741
1758
  // src/mcp/resources/utils.ts
1742
- import * as fs13 from "fs";
1743
- import * as path15 from "path";
1759
+ import * as fs14 from "fs";
1760
+ import * as path16 from "path";
1744
1761
  import ignore from "ignore";
1745
1762
  function estimateTokens(text2) {
1746
1763
  return Math.ceil(text2.length / 4);
1747
1764
  }
1748
1765
  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;
1766
+ const gitignorePath = path16.join(scanRoot, ".gitignore");
1767
+ const ig = fs14.existsSync(gitignorePath) ? ignore().add(fs14.readFileSync(gitignorePath, "utf-8")) : null;
1751
1768
  const toPosixRelativePath = (absolutePath) => {
1752
- const rel = path15.relative(scanRoot, absolutePath);
1753
- return rel.split(path15.sep).join("/");
1769
+ const rel = path16.relative(scanRoot, absolutePath);
1770
+ return rel.split(path16.sep).join("/");
1754
1771
  };
1755
1772
  const isUnderGitDir = (absolutePath) => {
1756
1773
  const rel = toPosixRelativePath(absolutePath);
@@ -1762,7 +1779,7 @@ function getScanContext(project, scanRoot) {
1762
1779
  return ig.ignores(isDir ? `${rel}/` : rel);
1763
1780
  };
1764
1781
  const shouldSkipEntryDir = (absolutePath) => {
1765
- const dirName = path15.basename(absolutePath);
1782
+ const dirName = path16.basename(absolutePath);
1766
1783
  if (dirName === ".git") return true;
1767
1784
  if (SKIP_DIRS.includes(dirName)) return true;
1768
1785
  if (isIgnoredByGitignore(absolutePath, true)) return true;
@@ -1783,7 +1800,7 @@ var init_utils2 = __esm({
1783
1800
  });
1784
1801
 
1785
1802
  // src/mcp/resources/paths.ts
1786
- import * as fs14 from "fs";
1803
+ import * as fs15 from "fs";
1787
1804
  function resolveProjectPaths(project, pathInput) {
1788
1805
  const config = loadMCPConfig();
1789
1806
  let workspaceRoot = pathInput;
@@ -1811,8 +1828,8 @@ function resolveProjectPaths(project, pathInput) {
1811
1828
  mode = "global";
1812
1829
  } else {
1813
1830
  mode = "workspace";
1814
- if (fs14.existsSync(configFilePath)) {
1815
- const content = fs14.readFileSync(configFilePath, "utf-8");
1831
+ if (fs15.existsSync(configFilePath)) {
1832
+ const content = fs15.readFileSync(configFilePath, "utf-8");
1816
1833
  if (content.includes("mode: global")) mode = "global";
1817
1834
  if (content.includes("mode: workspace")) mode = "workspace";
1818
1835
  }
@@ -1840,8 +1857,8 @@ var init_paths2 = __esm({
1840
1857
  });
1841
1858
 
1842
1859
  // src/mcp/resources/projects.ts
1843
- import * as fs15 from "fs";
1844
- import * as path16 from "path";
1860
+ import * as fs16 from "fs";
1861
+ import * as path17 from "path";
1845
1862
  function getExposedProjects() {
1846
1863
  const config = loadMCPConfig();
1847
1864
  const knownProjects = config.projects.filter((p) => !!p.path).map((p) => ({ name: p.name, path: p.path }));
@@ -1850,10 +1867,10 @@ function getExposedProjects() {
1850
1867
  const potentialProjects = [...allProjects];
1851
1868
  if (activeProject) {
1852
1869
  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");
1870
+ if (fs16.existsSync(path17.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
1871
+ cfgContent = fs16.readFileSync(path17.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
1872
+ } else if (fs16.existsSync(path17.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
1873
+ cfgContent = fs16.readFileSync(path17.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
1857
1874
  }
1858
1875
  if (cfgContent) {
1859
1876
  if (cfgContent.includes("linked_projects:")) {
@@ -1911,15 +1928,15 @@ function getProjectContext(projectName) {
1911
1928
  if (!project.knowledgePath) {
1912
1929
  return null;
1913
1930
  }
1914
- const contextPath = path16.join(project.knowledgePath, "project-context.md");
1915
- if (!fs15.existsSync(contextPath)) {
1931
+ const contextPath = path17.join(project.knowledgePath, "project-context.md");
1932
+ if (!fs16.existsSync(contextPath)) {
1916
1933
  return null;
1917
1934
  }
1918
- return fs15.readFileSync(contextPath, "utf-8");
1935
+ return fs16.readFileSync(contextPath, "utf-8");
1919
1936
  }
1920
1937
  function getCodeIndexPath(project) {
1921
1938
  const scanRoot = project.path || project.dataPath;
1922
- return path16.join(project.knowledgePath || path16.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
1939
+ return path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
1923
1940
  }
1924
1941
  var init_projects = __esm({
1925
1942
  "src/mcp/resources/projects.ts"() {
@@ -1932,8 +1949,8 @@ var init_projects = __esm({
1932
1949
  });
1933
1950
 
1934
1951
  // src/mcp/resources/tasks.ts
1935
- import * as fs16 from "fs";
1936
- import * as path17 from "path";
1952
+ import * as fs17 from "fs";
1953
+ import * as path18 from "path";
1937
1954
  import * as os3 from "os";
1938
1955
  import * as crypto from "crypto";
1939
1956
  function getProjectTasks(projectName) {
@@ -1947,18 +1964,18 @@ function getProjectTasks(projectName) {
1947
1964
  if (!permissions.tasks) {
1948
1965
  return [];
1949
1966
  }
1950
- if (!project.tasksPath || !fs16.existsSync(project.tasksPath)) {
1967
+ if (!project.tasksPath || !fs17.existsSync(project.tasksPath)) {
1951
1968
  return [];
1952
1969
  }
1953
1970
  const tasks = [];
1954
1971
  try {
1955
- const taskDirs = fs16.readdirSync(project.tasksPath, { withFileTypes: true });
1972
+ const taskDirs = fs17.readdirSync(project.tasksPath, { withFileTypes: true });
1956
1973
  for (const dir of taskDirs) {
1957
1974
  if (!dir.isDirectory()) continue;
1958
- const metaPath = path17.join(project.tasksPath, dir.name, "meta.json");
1959
- if (fs16.existsSync(metaPath)) {
1975
+ const metaPath = path18.join(project.tasksPath, dir.name, "meta.json");
1976
+ if (fs17.existsSync(metaPath)) {
1960
1977
  try {
1961
- const meta = JSON.parse(fs16.readFileSync(metaPath, "utf-8"));
1978
+ const meta = JSON.parse(fs17.readFileSync(metaPath, "utf-8"));
1962
1979
  tasks.push(meta);
1963
1980
  } catch (err) {
1964
1981
  logger.error(`[getProjectTasks] Failed to parse meta.json in ${dir.name}`, err);
@@ -1975,10 +1992,10 @@ function getTask(projectName, taskSlug) {
1975
1992
  const projects = projectService.scan();
1976
1993
  const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
1977
1994
  if (!project || !project.tasksPath) return null;
1978
- const metaPath = path17.join(project.tasksPath, taskSlug, "meta.json");
1979
- if (!fs16.existsSync(metaPath)) return null;
1995
+ const metaPath = path18.join(project.tasksPath, taskSlug, "meta.json");
1996
+ if (!fs17.existsSync(metaPath)) return null;
1980
1997
  try {
1981
- return JSON.parse(fs16.readFileSync(metaPath, "utf-8"));
1998
+ return JSON.parse(fs17.readFileSync(metaPath, "utf-8"));
1982
1999
  } catch (err) {
1983
2000
  logger.error(`[getTask] Failed to parse meta.json for task ${taskSlug}`, err);
1984
2001
  return null;
@@ -1991,26 +2008,26 @@ async function createTask(projectName, taskSlug, taskData) {
1991
2008
  if (!project || !project.tasksPath) {
1992
2009
  throw new Error(`Project '${projectName}' not found or not configured with a tasks path.`);
1993
2010
  }
1994
- const taskDir = path17.join(project.tasksPath, taskSlug);
1995
- if (fs16.existsSync(taskDir)) {
2011
+ const taskDir = path18.join(project.tasksPath, taskSlug);
2012
+ if (fs17.existsSync(taskDir)) {
1996
2013
  throw new Error(`Task with slug '${taskSlug}' already exists.`);
1997
2014
  }
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");
2015
+ fs17.mkdirSync(taskDir, { recursive: true });
2016
+ fs17.mkdirSync(path18.join(taskDir, "research"), { recursive: true });
2017
+ fs17.mkdirSync(path18.join(taskDir, "planning"), { recursive: true });
2018
+ fs17.mkdirSync(path18.join(taskDir, "execution"), { recursive: true });
2019
+ fs17.mkdirSync(path18.join(taskDir, "docs"), { recursive: true });
2020
+ const rrceHome = process.env.RRCE_HOME || path18.join(os3.homedir(), ".rrce-workflow");
2021
+ const templatePath = path18.join(rrceHome, "templates", "meta.template.json");
2005
2022
  let meta = {
2006
2023
  task_id: crypto.randomUUID(),
2007
2024
  task_slug: taskSlug,
2008
2025
  status: "draft",
2009
2026
  agents: {}
2010
2027
  };
2011
- if (fs16.existsSync(templatePath)) {
2028
+ if (fs17.existsSync(templatePath)) {
2012
2029
  try {
2013
- const template = JSON.parse(fs16.readFileSync(templatePath, "utf-8"));
2030
+ const template = JSON.parse(fs17.readFileSync(templatePath, "utf-8"));
2014
2031
  meta = { ...template, ...meta };
2015
2032
  } catch (e) {
2016
2033
  logger.error("Failed to load meta template", e);
@@ -2024,8 +2041,8 @@ async function createTask(projectName, taskSlug, taskData) {
2024
2041
  hash: project.name
2025
2042
  };
2026
2043
  Object.assign(meta, taskData);
2027
- const metaPath = path17.join(taskDir, "meta.json");
2028
- fs16.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
2044
+ const metaPath = path18.join(taskDir, "meta.json");
2045
+ fs17.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
2029
2046
  return meta;
2030
2047
  }
2031
2048
  async function updateTask(projectName, taskSlug, taskData) {
@@ -2044,8 +2061,8 @@ async function updateTask(projectName, taskSlug, taskData) {
2044
2061
  const projects = projectService.scan();
2045
2062
  const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
2046
2063
  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));
2064
+ const metaPath = path18.join(project.tasksPath, taskSlug, "meta.json");
2065
+ fs17.writeFileSync(metaPath, JSON.stringify(updatedMeta, null, 2));
2049
2066
  return updatedMeta;
2050
2067
  }
2051
2068
  function deleteTask(projectName, taskSlug) {
@@ -2053,12 +2070,12 @@ function deleteTask(projectName, taskSlug) {
2053
2070
  const projects = projectService.scan();
2054
2071
  const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
2055
2072
  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 });
2073
+ const taskDir = path18.join(project.tasksPath, taskSlug);
2074
+ if (!fs17.existsSync(taskDir)) return false;
2075
+ if (fs17.rmSync) {
2076
+ fs17.rmSync(taskDir, { recursive: true, force: true });
2060
2077
  } else {
2061
- fs16.rmdirSync(taskDir, { recursive: true });
2078
+ fs17.rmdirSync(taskDir, { recursive: true });
2062
2079
  }
2063
2080
  return true;
2064
2081
  }
@@ -2072,8 +2089,8 @@ var init_tasks = __esm({
2072
2089
  });
2073
2090
 
2074
2091
  // src/mcp/services/rag.ts
2075
- import * as fs17 from "fs";
2076
- import * as path18 from "path";
2092
+ import * as fs18 from "fs";
2093
+ import * as path19 from "path";
2077
2094
  var INDEX_VERSION, DEFAULT_MODEL, RAGService;
2078
2095
  var init_rag = __esm({
2079
2096
  "src/mcp/services/rag.ts"() {
@@ -2127,9 +2144,9 @@ var init_rag = __esm({
2127
2144
  */
2128
2145
  loadIndex() {
2129
2146
  if (this.index) return;
2130
- if (fs17.existsSync(this.indexPath)) {
2147
+ if (fs18.existsSync(this.indexPath)) {
2131
2148
  try {
2132
- const data = fs17.readFileSync(this.indexPath, "utf-8");
2149
+ const data = fs18.readFileSync(this.indexPath, "utf-8");
2133
2150
  this.index = JSON.parse(data);
2134
2151
  logger.info(`[RAG] Loaded index from ${this.indexPath} with ${this.index?.chunks.length} chunks.`);
2135
2152
  } catch (error) {
@@ -2155,11 +2172,11 @@ var init_rag = __esm({
2155
2172
  saveIndex() {
2156
2173
  if (!this.index) return;
2157
2174
  try {
2158
- const dir = path18.dirname(this.indexPath);
2159
- if (!fs17.existsSync(dir)) {
2160
- fs17.mkdirSync(dir, { recursive: true });
2175
+ const dir = path19.dirname(this.indexPath);
2176
+ if (!fs18.existsSync(dir)) {
2177
+ fs18.mkdirSync(dir, { recursive: true });
2161
2178
  }
2162
- fs17.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
2179
+ fs18.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
2163
2180
  logger.info(`[RAG] Saved index to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
2164
2181
  } catch (error) {
2165
2182
  logger.error(`[RAG] Failed to save index to ${this.indexPath}`, error);
@@ -2170,13 +2187,13 @@ var init_rag = __esm({
2170
2187
  */
2171
2188
  saveIndexAtomic() {
2172
2189
  if (!this.index) return;
2173
- const dir = path18.dirname(this.indexPath);
2174
- if (!fs17.existsSync(dir)) {
2175
- fs17.mkdirSync(dir, { recursive: true });
2190
+ const dir = path19.dirname(this.indexPath);
2191
+ if (!fs18.existsSync(dir)) {
2192
+ fs18.mkdirSync(dir, { recursive: true });
2176
2193
  }
2177
2194
  const tmpPath = `${this.indexPath}.tmp`;
2178
- fs17.writeFileSync(tmpPath, JSON.stringify(this.index, null, 2));
2179
- fs17.renameSync(tmpPath, this.indexPath);
2195
+ fs18.writeFileSync(tmpPath, JSON.stringify(this.index, null, 2));
2196
+ fs18.renameSync(tmpPath, this.indexPath);
2180
2197
  }
2181
2198
  /**
2182
2199
  * Save index only if enough time passed since last save
@@ -2709,10 +2726,10 @@ var init_context_extractor = __esm({
2709
2726
  });
2710
2727
 
2711
2728
  // src/mcp/services/dependency-graph.ts
2712
- import * as fs18 from "fs";
2713
- import * as path19 from "path";
2729
+ import * as fs19 from "fs";
2730
+ import * as path20 from "path";
2714
2731
  function parseImports(filePath, content) {
2715
- const ext = path19.extname(filePath).toLowerCase();
2732
+ const ext = path20.extname(filePath).toLowerCase();
2716
2733
  const language = getLanguageFromExtension(ext);
2717
2734
  const edges = [];
2718
2735
  const patterns = IMPORT_PATTERNS[language] || IMPORT_PATTERNS.javascript || [];
@@ -2742,20 +2759,20 @@ function parseImports(filePath, content) {
2742
2759
  return edges;
2743
2760
  }
2744
2761
  function resolveImport(fromFile, importPath, language) {
2745
- const fromDir = path19.dirname(fromFile);
2762
+ const fromDir = path20.dirname(fromFile);
2746
2763
  if (importPath.startsWith(".")) {
2747
- const candidates = generateCandidates(path19.resolve(fromDir, importPath), language);
2764
+ const candidates = generateCandidates(path20.resolve(fromDir, importPath), language);
2748
2765
  for (const candidate of candidates) {
2749
- if (fs18.existsSync(candidate)) {
2766
+ if (fs19.existsSync(candidate)) {
2750
2767
  return { path: candidate, isResolved: true };
2751
2768
  }
2752
2769
  }
2753
- return { path: path19.resolve(fromDir, importPath), isResolved: false };
2770
+ return { path: path20.resolve(fromDir, importPath), isResolved: false };
2754
2771
  }
2755
2772
  if (importPath.startsWith("/")) {
2756
2773
  const candidates = generateCandidates(importPath, language);
2757
2774
  for (const candidate of candidates) {
2758
- if (fs18.existsSync(candidate)) {
2775
+ if (fs19.existsSync(candidate)) {
2759
2776
  return { path: candidate, isResolved: true };
2760
2777
  }
2761
2778
  }
@@ -2765,7 +2782,7 @@ function resolveImport(fromFile, importPath, language) {
2765
2782
  }
2766
2783
  function generateCandidates(basePath, language) {
2767
2784
  const candidates = [];
2768
- if (path19.extname(basePath)) {
2785
+ if (path20.extname(basePath)) {
2769
2786
  candidates.push(basePath);
2770
2787
  }
2771
2788
  switch (language) {
@@ -2880,18 +2897,18 @@ async function scanProjectDependencies(projectRoot, options = {}) {
2880
2897
  const files = [];
2881
2898
  function scanDir(dir) {
2882
2899
  try {
2883
- const entries = fs18.readdirSync(dir, { withFileTypes: true });
2900
+ const entries = fs19.readdirSync(dir, { withFileTypes: true });
2884
2901
  for (const entry of entries) {
2885
- const fullPath = path19.join(dir, entry.name);
2902
+ const fullPath = path20.join(dir, entry.name);
2886
2903
  if (entry.isDirectory()) {
2887
2904
  if (!skipDirs.includes(entry.name) && !entry.name.startsWith(".")) {
2888
2905
  scanDir(fullPath);
2889
2906
  }
2890
2907
  } else if (entry.isFile()) {
2891
- const ext = path19.extname(entry.name).toLowerCase();
2908
+ const ext = path20.extname(entry.name).toLowerCase();
2892
2909
  if (extensions.includes(ext)) {
2893
2910
  try {
2894
- const content = fs18.readFileSync(fullPath, "utf-8");
2911
+ const content = fs19.readFileSync(fullPath, "utf-8");
2895
2912
  files.push({ path: fullPath, content });
2896
2913
  } catch {
2897
2914
  }
@@ -3188,9 +3205,53 @@ var init_symbol_extractor = __esm({
3188
3205
  }
3189
3206
  });
3190
3207
 
3208
+ // src/mcp/resources/search-utils.ts
3209
+ function getSearchAdvisory(projectName) {
3210
+ const indexingInProgress = indexingJobs.isRunning(projectName);
3211
+ const advisoryMessage = indexingInProgress ? "Indexing in progress; results may be stale/incomplete." : void 0;
3212
+ return { indexingInProgress, advisoryMessage };
3213
+ }
3214
+ function getIndexFreshness(projectName) {
3215
+ const progress = indexingJobs.getProgress(projectName);
3216
+ if (progress.completedAt) {
3217
+ return {
3218
+ lastIndexedAt: new Date(progress.completedAt).toISOString(),
3219
+ indexAgeSeconds: Math.floor((Date.now() - progress.completedAt) / 1e3)
3220
+ };
3221
+ }
3222
+ return {};
3223
+ }
3224
+ function applyTokenBudget(results, maxTokens, getContent) {
3225
+ let truncated = false;
3226
+ let tokenCount = 0;
3227
+ if (maxTokens !== void 0 && maxTokens > 0) {
3228
+ const budgeted = [];
3229
+ for (const result of results) {
3230
+ const resultTokens = estimateTokens(getContent(result));
3231
+ if (tokenCount + resultTokens > maxTokens) {
3232
+ truncated = true;
3233
+ break;
3234
+ }
3235
+ budgeted.push(result);
3236
+ tokenCount += resultTokens;
3237
+ }
3238
+ return { budgetedResults: budgeted, truncated, tokenCount };
3239
+ } else {
3240
+ tokenCount = results.reduce((sum, r) => sum + estimateTokens(getContent(r)), 0);
3241
+ return { budgetedResults: results, truncated: false, tokenCount };
3242
+ }
3243
+ }
3244
+ var init_search_utils = __esm({
3245
+ "src/mcp/resources/search-utils.ts"() {
3246
+ "use strict";
3247
+ init_indexing_jobs();
3248
+ init_utils2();
3249
+ }
3250
+ });
3251
+
3191
3252
  // src/mcp/resources/search.ts
3192
- import * as fs19 from "fs";
3193
- import * as path20 from "path";
3253
+ import * as fs20 from "fs";
3254
+ import * as path21 from "path";
3194
3255
  async function searchCode(query, projectFilter, limit = 10, options) {
3195
3256
  const config = loadMCPConfig();
3196
3257
  const projects = getExposedProjects();
@@ -3199,8 +3260,7 @@ async function searchCode(query, projectFilter, limit = 10, options) {
3199
3260
  if (projectFilter && project.name !== projectFilter) continue;
3200
3261
  const permissions = getProjectPermissions(config, project.name, project.sourcePath || project.path);
3201
3262
  if (!permissions.knowledge || !project.knowledgePath) continue;
3202
- const indexingInProgress2 = indexingJobs.isRunning(project.name);
3203
- const advisoryMessage2 = indexingInProgress2 ? "Indexing in progress; results may be stale/incomplete." : void 0;
3263
+ const { indexingInProgress, advisoryMessage } = getSearchAdvisory(project.name);
3204
3264
  const projConfig = findProjectConfig(config, { name: project.name, path: project.sourcePath || project.path });
3205
3265
  const useRAG = projConfig?.semanticSearch?.enabled;
3206
3266
  if (!useRAG) {
@@ -3209,7 +3269,7 @@ async function searchCode(query, projectFilter, limit = 10, options) {
3209
3269
  }
3210
3270
  try {
3211
3271
  const codeIndexPath = getCodeIndexPath(project);
3212
- if (!fs19.existsSync(codeIndexPath)) {
3272
+ if (!fs20.existsSync(codeIndexPath)) {
3213
3273
  logger.debug(`[searchCode] Code index not found for project '${project.name}'`);
3214
3274
  continue;
3215
3275
  }
@@ -3219,15 +3279,13 @@ async function searchCode(query, projectFilter, limit = 10, options) {
3219
3279
  const codeChunk = r;
3220
3280
  results.push({
3221
3281
  project: project.name,
3222
- file: path20.relative(project.sourcePath || project.path || "", codeChunk.filePath),
3282
+ file: path21.relative(project.sourcePath || project.path || "", codeChunk.filePath),
3223
3283
  snippet: codeChunk.content,
3224
3284
  lineStart: codeChunk.lineStart ?? 1,
3225
3285
  lineEnd: codeChunk.lineEnd ?? 1,
3226
3286
  context: codeChunk.context,
3227
3287
  language: codeChunk.language,
3228
- score: codeChunk.score,
3229
- indexingInProgress: indexingInProgress2 || void 0,
3230
- advisoryMessage: advisoryMessage2
3288
+ score: codeChunk.score
3231
3289
  });
3232
3290
  }
3233
3291
  } catch (e) {
@@ -3239,49 +3297,32 @@ async function searchCode(query, projectFilter, limit = 10, options) {
3239
3297
  if (options?.min_score !== void 0 && options.min_score > 0) {
3240
3298
  filteredResults = results.filter((r) => r.score >= options.min_score);
3241
3299
  }
3242
- let limitedResults = filteredResults.slice(0, limit);
3243
- let truncated = false;
3244
- let tokenCount = 0;
3245
- if (options?.max_tokens !== void 0 && options.max_tokens > 0) {
3246
- const budgetedResults = [];
3247
- for (const result of limitedResults) {
3248
- const resultTokens = estimateTokens(result.snippet + (result.context || ""));
3249
- if (tokenCount + resultTokens > options.max_tokens) {
3250
- truncated = true;
3251
- break;
3252
- }
3253
- budgetedResults.push(result);
3254
- tokenCount += resultTokens;
3255
- }
3256
- limitedResults = budgetedResults;
3257
- } else {
3258
- tokenCount = limitedResults.reduce((sum, r) => sum + estimateTokens(r.snippet + (r.context || "")), 0);
3259
- }
3300
+ const limitedResults = filteredResults.slice(0, limit);
3301
+ const { budgetedResults, truncated, tokenCount } = applyTokenBudget(
3302
+ limitedResults,
3303
+ options?.max_tokens,
3304
+ (r) => r.snippet + (r.context || "")
3305
+ );
3260
3306
  let indexAgeSeconds;
3261
3307
  let lastIndexedAt;
3262
- let indexingInProgress;
3263
- let advisoryMessage;
3308
+ let indexingInProgressGlobal;
3309
+ let advisoryMessageGlobal;
3264
3310
  if (projectFilter) {
3265
- const project = projects.find((p) => p.name === projectFilter);
3266
- if (project) {
3267
- indexingInProgress = indexingJobs.isRunning(project.name);
3268
- advisoryMessage = indexingInProgress ? "Indexing in progress; results may be stale/incomplete." : void 0;
3269
- const progress = indexingJobs.getProgress(project.name);
3270
- if (progress.completedAt) {
3271
- lastIndexedAt = new Date(progress.completedAt).toISOString();
3272
- indexAgeSeconds = Math.floor((Date.now() - progress.completedAt) / 1e3);
3273
- }
3274
- }
3311
+ const { indexingInProgress, advisoryMessage } = getSearchAdvisory(projectFilter);
3312
+ const freshness = getIndexFreshness(projectFilter);
3313
+ indexingInProgressGlobal = indexingInProgress;
3314
+ advisoryMessageGlobal = advisoryMessage;
3315
+ indexAgeSeconds = freshness.indexAgeSeconds;
3316
+ lastIndexedAt = freshness.lastIndexedAt;
3275
3317
  }
3276
- const cleanResults = limitedResults.map(({ indexingInProgress: _, advisoryMessage: __, ...rest }) => rest);
3277
3318
  return {
3278
- results: cleanResults,
3319
+ results: budgetedResults,
3279
3320
  token_count: tokenCount,
3280
3321
  truncated,
3281
3322
  index_age_seconds: indexAgeSeconds,
3282
3323
  last_indexed_at: lastIndexedAt,
3283
- indexingInProgress,
3284
- advisoryMessage
3324
+ indexingInProgress: indexingInProgressGlobal,
3325
+ advisoryMessage: advisoryMessageGlobal
3285
3326
  };
3286
3327
  }
3287
3328
  async function searchKnowledge(query, projectFilter, options) {
@@ -3293,24 +3334,20 @@ async function searchKnowledge(query, projectFilter, options) {
3293
3334
  if (projectFilter && project.name !== projectFilter) continue;
3294
3335
  const permissions = getProjectPermissions(config, project.name, project.sourcePath || project.path);
3295
3336
  if (!permissions.knowledge || !project.knowledgePath) continue;
3296
- const indexingInProgress2 = indexingJobs.isRunning(project.name);
3297
- const advisoryMessage2 = indexingInProgress2 ? "Indexing in progress; results may be stale/incomplete." : void 0;
3337
+ const { indexingInProgress, advisoryMessage } = getSearchAdvisory(project.name);
3298
3338
  const projConfig = findProjectConfig(config, { name: project.name, path: project.sourcePath || project.path });
3299
3339
  const useRAG = projConfig?.semanticSearch?.enabled;
3300
3340
  if (useRAG) {
3301
- logger.info(`[RAG] Using semantic search for project '${project.name}'`);
3302
3341
  try {
3303
- const indexPath = path20.join(project.knowledgePath, "embeddings.json");
3342
+ const indexPath = path21.join(project.knowledgePath, "embeddings.json");
3304
3343
  const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
3305
3344
  const ragResults = await rag.search(query, 5);
3306
3345
  for (const r of ragResults) {
3307
3346
  results.push({
3308
3347
  project: project.name,
3309
- file: path20.relative(project.knowledgePath, r.filePath),
3348
+ file: path21.relative(project.knowledgePath, r.filePath),
3310
3349
  matches: [r.content],
3311
- score: r.score,
3312
- indexingInProgress: indexingInProgress2 || void 0,
3313
- advisoryMessage: advisoryMessage2
3350
+ score: r.score
3314
3351
  });
3315
3352
  }
3316
3353
  continue;
@@ -3319,11 +3356,11 @@ async function searchKnowledge(query, projectFilter, options) {
3319
3356
  }
3320
3357
  }
3321
3358
  try {
3322
- const files = fs19.readdirSync(project.knowledgePath);
3359
+ const files = fs20.readdirSync(project.knowledgePath);
3323
3360
  for (const file of files) {
3324
3361
  if (!file.endsWith(".md")) continue;
3325
- const filePath = path20.join(project.knowledgePath, file);
3326
- const content = fs19.readFileSync(filePath, "utf-8");
3362
+ const filePath = path21.join(project.knowledgePath, file);
3363
+ const content = fs20.readFileSync(filePath, "utf-8");
3327
3364
  const lines = content.split("\n");
3328
3365
  const matches = [];
3329
3366
  for (const line of lines) {
@@ -3335,10 +3372,7 @@ async function searchKnowledge(query, projectFilter, options) {
3335
3372
  results.push({
3336
3373
  project: project.name,
3337
3374
  file,
3338
- matches: matches.slice(0, 5),
3339
- // Limit to 5 matches per file
3340
- indexingInProgress: indexingInProgress2 || void 0,
3341
- advisoryMessage: advisoryMessage2
3375
+ matches: matches.slice(0, 5)
3342
3376
  });
3343
3377
  }
3344
3378
  }
@@ -3351,48 +3385,31 @@ async function searchKnowledge(query, projectFilter, options) {
3351
3385
  filteredResults = results.filter((r) => (r.score ?? 1) >= options.min_score);
3352
3386
  }
3353
3387
  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);
3370
- }
3388
+ const { budgetedResults, truncated, tokenCount } = applyTokenBudget(
3389
+ filteredResults,
3390
+ options?.max_tokens,
3391
+ (r) => r.matches.join("\n")
3392
+ );
3371
3393
  let indexAgeSeconds;
3372
3394
  let lastIndexedAt;
3373
- let indexingInProgress;
3374
- let advisoryMessage;
3395
+ let indexingInProgressGlobal;
3396
+ let advisoryMessageGlobal;
3375
3397
  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
- }
3385
- }
3398
+ const { indexingInProgress, advisoryMessage } = getSearchAdvisory(projectFilter);
3399
+ const freshness = getIndexFreshness(projectFilter);
3400
+ indexingInProgressGlobal = indexingInProgress;
3401
+ advisoryMessageGlobal = advisoryMessage;
3402
+ indexAgeSeconds = freshness.indexAgeSeconds;
3403
+ lastIndexedAt = freshness.lastIndexedAt;
3386
3404
  }
3387
- const cleanResults = budgetedResults.map(({ indexingInProgress: _, advisoryMessage: __, ...rest }) => rest);
3388
3405
  return {
3389
- results: cleanResults,
3406
+ results: budgetedResults,
3390
3407
  token_count: tokenCount,
3391
3408
  truncated,
3392
3409
  index_age_seconds: indexAgeSeconds,
3393
3410
  last_indexed_at: lastIndexedAt,
3394
- indexingInProgress,
3395
- advisoryMessage
3411
+ indexingInProgress: indexingInProgressGlobal,
3412
+ advisoryMessage: advisoryMessageGlobal
3396
3413
  };
3397
3414
  }
3398
3415
  async function findRelatedFiles2(filePath, projectName, options = {}) {
@@ -3410,10 +3427,10 @@ async function findRelatedFiles2(filePath, projectName, options = {}) {
3410
3427
  }
3411
3428
  const projectRoot = project.sourcePath || project.path || "";
3412
3429
  let absoluteFilePath = filePath;
3413
- if (!path20.isAbsolute(filePath)) {
3414
- absoluteFilePath = path20.resolve(projectRoot, filePath);
3430
+ if (!path21.isAbsolute(filePath)) {
3431
+ absoluteFilePath = path21.resolve(projectRoot, filePath);
3415
3432
  }
3416
- if (!fs19.existsSync(absoluteFilePath)) {
3433
+ if (!fs20.existsSync(absoluteFilePath)) {
3417
3434
  return {
3418
3435
  success: false,
3419
3436
  file: filePath,
@@ -3430,13 +3447,13 @@ async function findRelatedFiles2(filePath, projectName, options = {}) {
3430
3447
  depth: options.depth ?? 1
3431
3448
  });
3432
3449
  const relationships = related.map((r) => ({
3433
- file: path20.relative(projectRoot, r.file),
3450
+ file: path21.relative(projectRoot, r.file),
3434
3451
  relationship: r.relationship,
3435
3452
  importPath: r.importPath
3436
3453
  }));
3437
3454
  return {
3438
3455
  success: true,
3439
- file: path20.relative(projectRoot, absoluteFilePath),
3456
+ file: path21.relative(projectRoot, absoluteFilePath),
3440
3457
  project: projectName,
3441
3458
  relationships
3442
3459
  };
@@ -3464,7 +3481,7 @@ async function searchSymbols2(name, projectName, options = {}) {
3464
3481
  };
3465
3482
  }
3466
3483
  const projectRoot = project.sourcePath || project.path || "";
3467
- if (!fs19.existsSync(projectRoot)) {
3484
+ if (!fs20.existsSync(projectRoot)) {
3468
3485
  return {
3469
3486
  success: false,
3470
3487
  project: projectName,
@@ -3475,14 +3492,14 @@ async function searchSymbols2(name, projectName, options = {}) {
3475
3492
  try {
3476
3493
  const codeFiles = [];
3477
3494
  const scanDir = (dir) => {
3478
- const entries = fs19.readdirSync(dir, { withFileTypes: true });
3495
+ const entries = fs20.readdirSync(dir, { withFileTypes: true });
3479
3496
  for (const entry of entries) {
3480
- const fullPath = path20.join(dir, entry.name);
3497
+ const fullPath = path21.join(dir, entry.name);
3481
3498
  if (entry.isDirectory()) {
3482
3499
  if (SKIP_DIRS.includes(entry.name)) continue;
3483
3500
  scanDir(fullPath);
3484
3501
  } else if (entry.isFile()) {
3485
- const ext = path20.extname(entry.name).toLowerCase();
3502
+ const ext = path21.extname(entry.name).toLowerCase();
3486
3503
  if (CODE_EXTENSIONS.includes(ext)) {
3487
3504
  codeFiles.push(fullPath);
3488
3505
  }
@@ -3493,7 +3510,7 @@ async function searchSymbols2(name, projectName, options = {}) {
3493
3510
  const symbolResults = [];
3494
3511
  for (const file of codeFiles.slice(0, 500)) {
3495
3512
  try {
3496
- const content = fs19.readFileSync(file, "utf-8");
3513
+ const content = fs20.readFileSync(file, "utf-8");
3497
3514
  const result = extractSymbols(content, file);
3498
3515
  symbolResults.push(result);
3499
3516
  } catch (e) {
@@ -3508,7 +3525,7 @@ async function searchSymbols2(name, projectName, options = {}) {
3508
3525
  const results = matches.map((m) => ({
3509
3526
  name: m.name,
3510
3527
  type: m.type,
3511
- file: path20.relative(projectRoot, m.file),
3528
+ file: path21.relative(projectRoot, m.file),
3512
3529
  line: m.line,
3513
3530
  signature: m.signature,
3514
3531
  exported: m.exported,
@@ -3541,24 +3558,24 @@ async function getFileSummary(filePath, projectName) {
3541
3558
  }
3542
3559
  const projectRoot = project.sourcePath || project.path || "";
3543
3560
  let absolutePath = filePath;
3544
- if (!path20.isAbsolute(filePath)) {
3545
- absolutePath = path20.resolve(projectRoot, filePath);
3561
+ if (!path21.isAbsolute(filePath)) {
3562
+ absolutePath = path21.resolve(projectRoot, filePath);
3546
3563
  }
3547
- if (!fs19.existsSync(absolutePath)) {
3564
+ if (!fs20.existsSync(absolutePath)) {
3548
3565
  return {
3549
3566
  success: false,
3550
3567
  message: `File not found: ${filePath}`
3551
3568
  };
3552
3569
  }
3553
3570
  try {
3554
- const stat = fs19.statSync(absolutePath);
3555
- const content = fs19.readFileSync(absolutePath, "utf-8");
3571
+ const stat = fs20.statSync(absolutePath);
3572
+ const content = fs20.readFileSync(absolutePath, "utf-8");
3556
3573
  const lines = content.split("\n");
3557
3574
  const symbolResult = extractSymbols(content, absolutePath);
3558
3575
  return {
3559
3576
  success: true,
3560
3577
  summary: {
3561
- path: path20.relative(projectRoot, absolutePath),
3578
+ path: path21.relative(projectRoot, absolutePath),
3562
3579
  language: symbolResult.language,
3563
3580
  lines: lines.length,
3564
3581
  size_bytes: stat.size,
@@ -3594,47 +3611,164 @@ var init_search = __esm({
3594
3611
  init_projects();
3595
3612
  init_utils2();
3596
3613
  init_constants();
3614
+ init_search_utils();
3597
3615
  }
3598
3616
  });
3599
3617
 
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",
3618
+ // src/lib/drift-service.ts
3619
+ import * as fs21 from "fs";
3620
+ import * as path22 from "path";
3621
+ import * as crypto2 from "crypto";
3622
+ var DriftService;
3623
+ var init_drift_service = __esm({
3624
+ "src/lib/drift-service.ts"() {
3625
+ "use strict";
3626
+ DriftService = class {
3627
+ static CHECKSUM_FILENAME = ".rrce-checksums.json";
3628
+ static calculateHash(filePath) {
3629
+ const content = fs21.readFileSync(filePath);
3630
+ return crypto2.createHash("md5").update(content).digest("hex");
3631
+ }
3632
+ static getManifestPath(projectPath) {
3633
+ return path22.join(projectPath, this.CHECKSUM_FILENAME);
3634
+ }
3635
+ static loadManifest(projectPath) {
3636
+ const manifestPath = this.getManifestPath(projectPath);
3637
+ if (!fs21.existsSync(manifestPath)) {
3638
+ return {};
3639
+ }
3640
+ try {
3641
+ return JSON.parse(fs21.readFileSync(manifestPath, "utf8"));
3642
+ } catch (e) {
3643
+ return {};
3644
+ }
3645
+ }
3646
+ static saveManifest(projectPath, manifest) {
3647
+ const manifestPath = this.getManifestPath(projectPath);
3648
+ fs21.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
3649
+ }
3650
+ /**
3651
+ * Generates a manifest for the current state of files in the project
3652
+ */
3653
+ static generateManifest(projectPath, files) {
3654
+ const manifest = {};
3655
+ for (const file of files) {
3656
+ const fullPath = path22.join(projectPath, file);
3657
+ if (fs21.existsSync(fullPath)) {
3658
+ const stats = fs21.statSync(fullPath);
3659
+ manifest[file] = {
3660
+ hash: this.calculateHash(fullPath),
3661
+ mtime: stats.mtimeMs
3662
+ };
3663
+ }
3664
+ }
3665
+ return manifest;
3666
+ }
3667
+ /**
3668
+ * Compares current files against the manifest to detect modifications and deletions
3669
+ */
3670
+ static detectModifiedFiles(projectPath) {
3671
+ const manifest = this.loadManifest(projectPath);
3672
+ const modified = [];
3673
+ const deleted = [];
3674
+ for (const [relPath, entry] of Object.entries(manifest)) {
3675
+ const fullPath = path22.join(projectPath, relPath);
3676
+ if (!fs21.existsSync(fullPath)) {
3677
+ deleted.push(relPath);
3678
+ continue;
3679
+ }
3680
+ const stats = fs21.statSync(fullPath);
3681
+ if (stats.mtimeMs === entry.mtime) {
3682
+ continue;
3683
+ }
3684
+ const currentHash = this.calculateHash(fullPath);
3685
+ if (currentHash !== entry.hash) {
3686
+ modified.push(relPath);
3687
+ }
3688
+ }
3689
+ return { modified, deleted };
3690
+ }
3691
+ /**
3692
+ * Returns array of deleted file paths from manifest
3693
+ */
3694
+ static detectDeletedFiles(projectPath) {
3695
+ const manifest = this.loadManifest(projectPath);
3696
+ const deleted = [];
3697
+ for (const relPath of Object.keys(manifest)) {
3698
+ const fullPath = path22.join(projectPath, relPath);
3699
+ if (!fs21.existsSync(fullPath)) {
3700
+ deleted.push(relPath);
3701
+ }
3702
+ }
3703
+ return deleted;
3704
+ }
3705
+ /**
3706
+ * Full drift check: version + modifications
3707
+ */
3708
+ static checkDrift(projectPath, currentVersion, runningVersion) {
3709
+ const { modified, deleted } = this.detectModifiedFiles(projectPath);
3710
+ let type = "none";
3711
+ let hasDrift = false;
3712
+ if (currentVersion !== runningVersion) {
3713
+ hasDrift = true;
3714
+ type = "version";
3715
+ } else if (modified.length > 0 || deleted.length > 0) {
3716
+ hasDrift = true;
3717
+ type = "modified";
3718
+ }
3719
+ return {
3720
+ hasDrift,
3721
+ type,
3722
+ modifiedFiles: modified,
3723
+ deletedFiles: deleted,
3724
+ version: {
3725
+ current: currentVersion || "0.0.0",
3726
+ running: runningVersion
3727
+ }
3728
+ };
3729
+ }
3730
+ };
3731
+ }
3732
+ });
3733
+
3734
+ // src/mcp/resources/indexing.ts
3735
+ import * as fs22 from "fs";
3736
+ import * as path23 from "path";
3737
+ async function indexKnowledge(projectName, force = false, clean = false) {
3738
+ const config = loadMCPConfig();
3739
+ const projects = getExposedProjects();
3740
+ const project = projects.find((p2) => p2.name === projectName || p2.path && p2.path === projectName);
3741
+ if (!project) {
3742
+ return {
3743
+ state: "failed",
3744
+ status: "failed",
3745
+ success: false,
3746
+ message: `Project '${projectName}' not found`,
3747
+ filesIndexed: 0,
3748
+ filesSkipped: 0,
3749
+ progress: { itemsDone: 0 }
3750
+ };
3751
+ }
3752
+ 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);
3753
+ const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
3754
+ if (!isEnabled) {
3755
+ return {
3756
+ state: "failed",
3757
+ status: "failed",
3758
+ success: false,
3759
+ message: "Semantic Search is not enabled for this project",
3760
+ filesIndexed: 0,
3761
+ filesSkipped: 0,
3762
+ progress: { itemsDone: 0 }
3763
+ };
3764
+ }
3765
+ const scanRoot = project.sourcePath || project.path || project.dataPath;
3766
+ if (!fs22.existsSync(scanRoot)) {
3767
+ return {
3768
+ state: "failed",
3769
+ status: "failed",
3770
+ success: false,
3771
+ message: "Project root not found",
3638
3772
  filesIndexed: 0,
3639
3773
  filesSkipped: 0,
3640
3774
  progress: { itemsDone: 0 }
@@ -3642,8 +3776,14 @@ async function indexKnowledge(projectName, force = false) {
3642
3776
  }
3643
3777
  const runIndexing = async () => {
3644
3778
  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");
3779
+ const knowledgeDir = project.knowledgePath || path23.join(scanRoot, ".rrce-workflow", "knowledge");
3780
+ const indexPath = path23.join(knowledgeDir, "embeddings.json");
3781
+ const codeIndexPath = path23.join(knowledgeDir, "code-embeddings.json");
3782
+ if (clean) {
3783
+ logger.info(`[RAG] Cleaning knowledge index for ${project.name}`);
3784
+ if (fs22.existsSync(indexPath)) fs22.unlinkSync(indexPath);
3785
+ if (fs22.existsSync(codeIndexPath)) fs22.unlinkSync(codeIndexPath);
3786
+ }
3647
3787
  const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
3648
3788
  const rag = new RAGService(indexPath, model);
3649
3789
  const codeRag = new RAGService(codeIndexPath, model);
@@ -3653,14 +3793,14 @@ async function indexKnowledge(projectName, force = false) {
3653
3793
  let itemsTotal = 0;
3654
3794
  let itemsDone = 0;
3655
3795
  const preCount = (dir) => {
3656
- const entries = fs20.readdirSync(dir, { withFileTypes: true });
3796
+ const entries = fs22.readdirSync(dir, { withFileTypes: true });
3657
3797
  for (const entry of entries) {
3658
- const fullPath = path21.join(dir, entry.name);
3798
+ const fullPath = path23.join(dir, entry.name);
3659
3799
  if (entry.isDirectory()) {
3660
3800
  if (shouldSkipEntryDir(fullPath)) continue;
3661
3801
  preCount(fullPath);
3662
3802
  } else if (entry.isFile()) {
3663
- const ext = path21.extname(entry.name).toLowerCase();
3803
+ const ext = path23.extname(entry.name).toLowerCase();
3664
3804
  if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
3665
3805
  if (shouldSkipEntryFile(fullPath)) continue;
3666
3806
  itemsTotal++;
@@ -3672,13 +3812,18 @@ async function indexKnowledge(projectName, force = false) {
3672
3812
  const cleanupIgnoredFiles = async () => {
3673
3813
  const indexedFiles = [...rag.getIndexedFiles(), ...codeRag.getIndexedFiles()];
3674
3814
  const unique = Array.from(new Set(indexedFiles));
3815
+ const deletedFiles = project.dataPath ? DriftService.detectDeletedFiles(project.dataPath) : [];
3816
+ if (deletedFiles.length > 0) {
3817
+ logger.info(`[RAG] ${project.name}: Detected ${deletedFiles.length} deleted files from manifest`);
3818
+ }
3675
3819
  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("/");
3820
+ if (!path23.isAbsolute(filePath)) continue;
3821
+ const relFilePath = filePath.split(path23.sep).join("/");
3822
+ const relScanRoot = scanRoot.split(path23.sep).join("/");
3679
3823
  const isInScanRoot = relFilePath === relScanRoot || relFilePath.startsWith(`${relScanRoot}/`);
3680
3824
  if (!isInScanRoot) continue;
3681
- if (shouldSkipEntryFile(filePath)) {
3825
+ const isDeleted = deletedFiles.some((df) => filePath.endsWith(df));
3826
+ if (shouldSkipEntryFile(filePath) || isDeleted || !fs22.existsSync(filePath)) {
3682
3827
  await rag.removeFile(filePath);
3683
3828
  await codeRag.removeFile(filePath);
3684
3829
  }
@@ -3686,21 +3831,21 @@ async function indexKnowledge(projectName, force = false) {
3686
3831
  };
3687
3832
  await cleanupIgnoredFiles();
3688
3833
  const scanDir = async (dir) => {
3689
- const entries = fs20.readdirSync(dir, { withFileTypes: true });
3834
+ const entries = fs22.readdirSync(dir, { withFileTypes: true });
3690
3835
  for (const entry of entries) {
3691
- const fullPath = path21.join(dir, entry.name);
3836
+ const fullPath = path23.join(dir, entry.name);
3692
3837
  if (entry.isDirectory()) {
3693
3838
  if (shouldSkipEntryDir(fullPath)) continue;
3694
3839
  await scanDir(fullPath);
3695
3840
  } else if (entry.isFile()) {
3696
- const ext = path21.extname(entry.name).toLowerCase();
3841
+ const ext = path23.extname(entry.name).toLowerCase();
3697
3842
  if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
3698
3843
  if (shouldSkipEntryFile(fullPath)) continue;
3699
3844
  try {
3700
3845
  indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
3701
- const stat = fs20.statSync(fullPath);
3846
+ const stat = fs22.statSync(fullPath);
3702
3847
  const mtime = force ? void 0 : stat.mtimeMs;
3703
- const content = fs20.readFileSync(fullPath, "utf-8");
3848
+ const content = fs22.readFileSync(fullPath, "utf-8");
3704
3849
  const wasIndexed = await rag.indexFile(fullPath, content, mtime);
3705
3850
  if (wasIndexed) {
3706
3851
  indexed++;
@@ -3772,11 +3917,12 @@ var init_indexing = __esm({
3772
3917
  init_projects();
3773
3918
  init_utils2();
3774
3919
  init_constants();
3920
+ init_drift_service();
3775
3921
  }
3776
3922
  });
3777
3923
 
3778
3924
  // src/mcp/resources/context.ts
3779
- import * as path22 from "path";
3925
+ import * as path24 from "path";
3780
3926
  import * as os4 from "os";
3781
3927
  function getContextPreamble() {
3782
3928
  const activeProject = detectActiveProject();
@@ -3792,7 +3938,7 @@ If the above tools fail, ask the user for clarification.
3792
3938
  ---
3793
3939
  `;
3794
3940
  }
3795
- const rrceHome = process.env.RRCE_HOME || path22.join(os4.homedir(), ".rrce-workflow");
3941
+ const rrceHome = process.env.RRCE_HOME || path24.join(os4.homedir(), ".rrce-workflow");
3796
3942
  const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
3797
3943
  const rrceData = activeProject.dataPath;
3798
3944
  return `## System Context
@@ -4087,8 +4233,8 @@ var init_validation = __esm({
4087
4233
  });
4088
4234
 
4089
4235
  // src/mcp/resources/sessions.ts
4090
- import * as fs21 from "fs";
4091
- import * as path23 from "path";
4236
+ import * as fs23 from "fs";
4237
+ import * as path25 from "path";
4092
4238
  function startSession(projectName, taskSlug, agent, phase) {
4093
4239
  const config = loadMCPConfig();
4094
4240
  const projects = projectService.scan();
@@ -4096,8 +4242,8 @@ function startSession(projectName, taskSlug, agent, phase) {
4096
4242
  if (!project || !project.tasksPath) {
4097
4243
  return { success: false, message: `Project '${projectName}' not found or not exposed.` };
4098
4244
  }
4099
- const taskDir = path23.join(project.tasksPath, taskSlug);
4100
- if (!fs21.existsSync(taskDir)) {
4245
+ const taskDir = path25.join(project.tasksPath, taskSlug);
4246
+ if (!fs23.existsSync(taskDir)) {
4101
4247
  return { success: false, message: `Task '${taskSlug}' not found.` };
4102
4248
  }
4103
4249
  const session = {
@@ -4107,8 +4253,8 @@ function startSession(projectName, taskSlug, agent, phase) {
4107
4253
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
4108
4254
  heartbeat: (/* @__PURE__ */ new Date()).toISOString()
4109
4255
  };
4110
- const sessionPath = path23.join(taskDir, "session.json");
4111
- fs21.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
4256
+ const sessionPath = path25.join(taskDir, "session.json");
4257
+ fs23.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
4112
4258
  return { success: true, message: `Session started for ${agent} agent on task '${taskSlug}' (phase: ${phase})` };
4113
4259
  }
4114
4260
  function endSession(projectName, taskSlug) {
@@ -4118,11 +4264,11 @@ function endSession(projectName, taskSlug) {
4118
4264
  if (!project || !project.tasksPath) {
4119
4265
  return { success: false, message: `Project '${projectName}' not found or not exposed.` };
4120
4266
  }
4121
- const sessionPath = path23.join(project.tasksPath, taskSlug, "session.json");
4122
- if (!fs21.existsSync(sessionPath)) {
4267
+ const sessionPath = path25.join(project.tasksPath, taskSlug, "session.json");
4268
+ if (!fs23.existsSync(sessionPath)) {
4123
4269
  return { success: true, message: `No active session for task '${taskSlug}'.` };
4124
4270
  }
4125
- fs21.unlinkSync(sessionPath);
4271
+ fs23.unlinkSync(sessionPath);
4126
4272
  return { success: true, message: `Session ended for task '${taskSlug}'.` };
4127
4273
  }
4128
4274
  function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
@@ -4132,9 +4278,9 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
4132
4278
  if (!project || !project.tasksPath) {
4133
4279
  return { success: false, message: `Project '${projectName}' not found or not exposed.` };
4134
4280
  }
4135
- const taskDir = path23.join(project.tasksPath, taskSlug);
4136
- if (!fs21.existsSync(taskDir)) {
4137
- fs21.mkdirSync(taskDir, { recursive: true });
4281
+ const taskDir = path25.join(project.tasksPath, taskSlug);
4282
+ if (!fs23.existsSync(taskDir)) {
4283
+ fs23.mkdirSync(taskDir, { recursive: true });
4138
4284
  }
4139
4285
  const todos = {
4140
4286
  phase,
@@ -4142,8 +4288,8 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
4142
4288
  items,
4143
4289
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
4144
4290
  };
4145
- const todosPath = path23.join(taskDir, "agent-todos.json");
4146
- fs21.writeFileSync(todosPath, JSON.stringify(todos, null, 2));
4291
+ const todosPath = path25.join(taskDir, "agent-todos.json");
4292
+ fs23.writeFileSync(todosPath, JSON.stringify(todos, null, 2));
4147
4293
  return { success: true, message: `Updated ${items.length} todo items for task '${taskSlug}'.`, count: items.length };
4148
4294
  }
4149
4295
  var init_sessions = __esm({
@@ -4263,143 +4409,69 @@ var init_resources3 = __esm({
4263
4409
  }
4264
4410
  });
4265
4411
 
4266
- // src/mcp/prompts.ts
4267
- import * as path24 from "path";
4268
- import * as fs22 from "fs";
4269
- function loadBaseProtocol2() {
4270
- if (baseProtocolCache !== null) {
4271
- return baseProtocolCache;
4272
- }
4273
- const basePath = path24.join(getAgentCorePromptsDir(), "_base.md");
4274
- if (fs22.existsSync(basePath)) {
4275
- const content = fs22.readFileSync(basePath, "utf-8");
4276
- baseProtocolCache = content.replace(/^---[\s\S]*?---\n*/, "");
4277
- return baseProtocolCache;
4278
- }
4279
- baseProtocolCache = "";
4280
- return "";
4281
- }
4282
- function getAllPrompts() {
4283
- const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
4284
- return prompts.map((p) => {
4285
- const args = [];
4286
- if (p.frontmatter["required-args"]) {
4287
- args.push(...p.frontmatter["required-args"].map((a) => ({
4288
- name: a.name,
4289
- description: a.prompt || a.name,
4290
- required: true
4291
- })));
4292
- }
4293
- if (p.frontmatter["optional-args"]) {
4294
- args.push(...p.frontmatter["optional-args"].map((a) => ({
4295
- name: a.name,
4296
- description: a.prompt || a.name,
4297
- required: false
4298
- })));
4412
+ // src/mcp/handlers/tools/project.ts
4413
+ async function handleProjectTool(name, args) {
4414
+ if (!args) {
4415
+ if (name === "list_projects" || name === "help_setup") {
4416
+ } else {
4417
+ return null;
4299
4418
  }
4300
- const filename = p.filePath.split("/").pop() || "";
4301
- const id = filename.replace(/\.md$/, "");
4302
- return {
4303
- id,
4304
- name: p.frontmatter.name,
4305
- description: p.frontmatter.description,
4306
- arguments: args,
4307
- content: p.content
4308
- };
4309
- });
4310
- }
4311
- function getPromptDef(name) {
4312
- const all = getAllPrompts();
4313
- const search = name.toLowerCase();
4314
- return all.find(
4315
- (p) => p.name === name || p.id === name || p.name.toLowerCase() === search || p.id.toLowerCase() === search
4316
- );
4317
- }
4318
- function renderPromptWithContext(content, args) {
4319
- const renderArgs = { ...args };
4320
- let activeProject = detectActiveProject();
4321
- if (!activeProject) {
4322
- projectService.refresh();
4323
- activeProject = detectActiveProject();
4324
4419
  }
4325
- const DEFAULT_RRCE_HOME = getEffectiveGlobalPath();
4326
- let resolvedRrceData = ".rrce-workflow/";
4327
- let resolvedRrceHome = DEFAULT_RRCE_HOME;
4328
- let resolvedWorkspaceRoot = process.cwd();
4329
- let resolvedWorkspaceName = "current-project";
4330
- if (activeProject) {
4331
- resolvedRrceData = activeProject.dataPath;
4332
- if (!resolvedRrceData.endsWith("/") && !resolvedRrceData.endsWith("\\")) {
4333
- resolvedRrceData += "/";
4420
+ switch (name) {
4421
+ case "resolve_path": {
4422
+ const params = args;
4423
+ const result = resolveProjectPaths(params.project, params.path);
4424
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4334
4425
  }
4335
- resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
4336
- resolvedWorkspaceName = activeProject.name;
4337
- if (activeProject.source === "global") {
4338
- const workspacesDir = path24.dirname(activeProject.dataPath);
4339
- resolvedRrceHome = path24.dirname(workspacesDir);
4426
+ case "list_projects": {
4427
+ const projects = getExposedProjects();
4428
+ const list = projects.map((p) => ({ name: p.name, source: p.source, path: p.path }));
4429
+ return {
4430
+ content: [{
4431
+ type: "text",
4432
+ text: JSON.stringify(list, null, 2) + "\n\nTip: Use these project names for tools like `get_project_context` or `index_knowledge`."
4433
+ }]
4434
+ };
4340
4435
  }
4341
- } else {
4342
- try {
4343
- const workspaceRoot = detectWorkspaceRoot();
4344
- const workspaceName = path24.basename(workspaceRoot);
4345
- const globalWorkspacePath = path24.join(DEFAULT_RRCE_HOME, "workspaces", workspaceName);
4346
- if (fs22.existsSync(globalWorkspacePath)) {
4347
- resolvedRrceData = globalWorkspacePath;
4348
- resolvedWorkspaceRoot = workspaceRoot;
4349
- resolvedWorkspaceName = workspaceName;
4350
- if (!resolvedRrceData.endsWith("/") && !resolvedRrceData.endsWith("\\")) {
4351
- resolvedRrceData += "/";
4352
- }
4436
+ case "get_project_context": {
4437
+ const context = getProjectContext(args.project);
4438
+ if (!context) {
4439
+ const projects = getExposedProjects().map((p) => p.name).join(", ");
4440
+ const msg = `No project context found for "${args.project}".
4441
+ Available projects: ${projects}`;
4442
+ logger.warn(msg);
4443
+ return { content: [{ type: "text", text: msg }], isError: true };
4353
4444
  }
4354
- } catch (e) {
4445
+ return { content: [{ type: "text", text: context }] };
4355
4446
  }
4356
- }
4357
- if (!renderArgs["RRCE_DATA"]) renderArgs["RRCE_DATA"] = resolvedRrceData;
4358
- if (!renderArgs["RRCE_HOME"]) renderArgs["RRCE_HOME"] = resolvedRrceHome;
4359
- if (!renderArgs["WORKSPACE_ROOT"]) renderArgs["WORKSPACE_ROOT"] = resolvedWorkspaceRoot;
4360
- if (!renderArgs["WORKSPACE_NAME"]) renderArgs["WORKSPACE_NAME"] = resolvedWorkspaceName;
4361
- const agentContent = renderPrompt(content, renderArgs);
4362
- const baseProtocol = loadBaseProtocol2();
4363
- const rendered = baseProtocol ? `${baseProtocol}
4364
- ${agentContent}` : agentContent;
4365
- return {
4366
- rendered,
4367
- context: {
4368
- RRCE_DATA: resolvedRrceData,
4369
- RRCE_HOME: resolvedRrceHome,
4370
- WORKSPACE_ROOT: resolvedWorkspaceRoot,
4371
- WORKSPACE_NAME: resolvedWorkspaceName
4447
+ case "index_knowledge": {
4448
+ const params = args;
4449
+ const result = await indexKnowledge(params.project, params.force, params.clean);
4450
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4372
4451
  }
4373
- };
4374
- }
4375
- function renderPrompt(content, args) {
4376
- let rendered = content;
4377
- for (const [key, val] of Object.entries(args)) {
4378
- rendered = rendered.replace(new RegExp(`{{${key}}}`, "g"), val);
4452
+ case "help_setup": {
4453
+ const msg = `
4454
+ RRCE MCP Server is running, but no projects are configured/exposed.
4455
+
4456
+ To fix this:
4457
+ 1. Open a terminal.
4458
+ 2. Run: npx rrce-workflow mcp configure
4459
+ 3. Select the projects you want to expose to the AI.
4460
+ 4. Restart the MCP server (or it may pick up changes automatically).
4461
+ `;
4462
+ return { content: [{ type: "text", text: msg }] };
4463
+ }
4464
+ default:
4465
+ return null;
4379
4466
  }
4380
- return rendered;
4381
4467
  }
4382
- var baseProtocolCache;
4383
- var init_prompts2 = __esm({
4384
- "src/mcp/prompts.ts"() {
4468
+ var projectTools;
4469
+ var init_project = __esm({
4470
+ "src/mcp/handlers/tools/project.ts"() {
4385
4471
  "use strict";
4386
- init_prompts();
4387
4472
  init_resources2();
4388
- init_paths();
4389
- init_detection_service();
4390
- baseProtocolCache = null;
4391
- }
4392
- });
4393
-
4394
- // src/mcp/handlers/tools.ts
4395
- import "@modelcontextprotocol/sdk/server/index.js";
4396
- import {
4397
- ListToolsRequestSchema,
4398
- CallToolRequestSchema
4399
- } from "@modelcontextprotocol/sdk/types.js";
4400
- function registerToolHandlers(server) {
4401
- server.setRequestHandler(ListToolsRequestSchema, async () => {
4402
- const tools = [
4473
+ init_logger();
4474
+ projectTools = [
4403
4475
  {
4404
4476
  name: "resolve_path",
4405
4477
  description: "Resolve configuration paths (RRCE_DATA, etc.) for a project. Helps determine if a project is using global or local storage.",
@@ -4411,6 +4483,124 @@ function registerToolHandlers(server) {
4411
4483
  }
4412
4484
  }
4413
4485
  },
4486
+ {
4487
+ name: "list_projects",
4488
+ description: "List all projects exposed via MCP. Use these names for project-specific tools.",
4489
+ inputSchema: { type: "object", properties: {} }
4490
+ },
4491
+ {
4492
+ name: "get_project_context",
4493
+ description: "Get the project context/architecture for a specific project",
4494
+ inputSchema: {
4495
+ type: "object",
4496
+ properties: { project: { type: "string", description: "Name of the project to get context for" } },
4497
+ required: ["project"]
4498
+ }
4499
+ },
4500
+ {
4501
+ name: "index_knowledge",
4502
+ description: "Update the semantic search index for a specific project",
4503
+ inputSchema: {
4504
+ type: "object",
4505
+ properties: {
4506
+ project: { type: "string", description: "Name of the project to index" },
4507
+ force: { type: "boolean", description: "Force re-indexing of all files" },
4508
+ clean: { type: "boolean", description: "Wipe existing index and rebuild from scratch" }
4509
+ },
4510
+ required: ["project"]
4511
+ }
4512
+ }
4513
+ ];
4514
+ }
4515
+ });
4516
+
4517
+ // src/mcp/handlers/tools/search.ts
4518
+ async function handleSearchTool(name, args) {
4519
+ if (!args) return null;
4520
+ switch (name) {
4521
+ case "search_knowledge": {
4522
+ const params = args;
4523
+ const result = await searchKnowledge(params.query, params.project, {
4524
+ max_tokens: params.max_tokens,
4525
+ min_score: params.min_score
4526
+ });
4527
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4528
+ }
4529
+ case "search_code": {
4530
+ const params = args;
4531
+ const result = await searchCode(params.query, params.project, params.limit, {
4532
+ max_tokens: params.max_tokens,
4533
+ min_score: params.min_score
4534
+ });
4535
+ if (result.results.length === 0) {
4536
+ return {
4537
+ content: [{
4538
+ type: "text",
4539
+ text: "No code matches found. The code index may be empty or semantic search is not enabled.\nRun `index_knowledge` first to build the code index."
4540
+ }]
4541
+ };
4542
+ }
4543
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4544
+ }
4545
+ case "find_related_files": {
4546
+ const params = args;
4547
+ const result = await findRelatedFiles2(params.file, params.project, {
4548
+ includeImports: params.include_imports,
4549
+ includeImportedBy: params.include_imported_by,
4550
+ depth: params.depth
4551
+ });
4552
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4553
+ }
4554
+ case "search_symbols": {
4555
+ const params = args;
4556
+ const result = await searchSymbols2(params.name, params.project, {
4557
+ type: params.type,
4558
+ fuzzy: params.fuzzy,
4559
+ limit: params.limit
4560
+ });
4561
+ if (!result.success) {
4562
+ return { content: [{ type: "text", text: result.message || "Search failed" }], isError: true };
4563
+ }
4564
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4565
+ }
4566
+ case "get_file_summary": {
4567
+ const params = args;
4568
+ const result = await getFileSummary(params.file, params.project);
4569
+ if (!result.success) {
4570
+ return { content: [{ type: "text", text: result.message || "Failed to get file summary" }], isError: true };
4571
+ }
4572
+ return { content: [{ type: "text", text: JSON.stringify(result.summary, null, 2) }] };
4573
+ }
4574
+ case "get_context_bundle": {
4575
+ const params = args;
4576
+ const result = await getContextBundle(params.query, params.project, {
4577
+ task_slug: params.task_slug,
4578
+ max_tokens: params.max_tokens,
4579
+ include: params.include
4580
+ });
4581
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4582
+ }
4583
+ case "prefetch_task_context": {
4584
+ const params = args;
4585
+ const result = await prefetchTaskContext(params.project, params.task_slug, {
4586
+ max_tokens: params.max_tokens
4587
+ });
4588
+ if (!result.success) {
4589
+ return { content: [{ type: "text", text: result.message || "Failed to prefetch task context" }], isError: true };
4590
+ }
4591
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4592
+ }
4593
+ default:
4594
+ return null;
4595
+ }
4596
+ }
4597
+ var searchTools;
4598
+ var init_search2 = __esm({
4599
+ "src/mcp/handlers/tools/search.ts"() {
4600
+ "use strict";
4601
+ init_resources2();
4602
+ init_logger();
4603
+ searchTools = [
4414
4604
  {
4415
4605
  name: "search_knowledge",
4416
4606
  description: "Search across all exposed project knowledge bases. Returns results with token count and optional truncation.",
@@ -4518,194 +4708,465 @@ function registerToolHandlers(server) {
4518
4708
  },
4519
4709
  required: ["project", "task_slug"]
4520
4710
  }
4521
- },
4711
+ }
4712
+ ];
4713
+ }
4714
+ });
4715
+
4716
+ // src/mcp/handlers/tools/task.ts
4717
+ async function handleTaskTool(name, args) {
4718
+ if (!args) return null;
4719
+ switch (name) {
4720
+ case "list_tasks": {
4721
+ const params = args;
4722
+ const tasks = getProjectTasks(params.project);
4723
+ return { content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }] };
4724
+ }
4725
+ case "get_task": {
4726
+ const params = args;
4727
+ const task = getTask(params.project, params.task_slug);
4728
+ if (!task) {
4729
+ return { content: [{ type: "text", text: `Task '${params.task_slug}' not found in project '${params.project}'.` }], isError: true };
4730
+ }
4731
+ return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
4732
+ }
4733
+ case "create_task": {
4734
+ const params = args;
4735
+ const taskData = {
4736
+ title: params.title || params.task_slug,
4737
+ summary: params.summary || ""
4738
+ };
4739
+ const task = await createTask(params.project, params.task_slug, taskData);
4740
+ return { content: [{ type: "text", text: `\u2713 Task '${params.task_slug}' created. meta.json saved.
4741
+ ${JSON.stringify(task, null, 2)}` }] };
4742
+ }
4743
+ case "update_task": {
4744
+ const params = args;
4745
+ const task = await updateTask(params.project, params.task_slug, params.updates);
4746
+ return { content: [{ type: "text", text: `\u2713 Task '${params.task_slug}' updated. meta.json saved.
4747
+ ${JSON.stringify(task, null, 2)}` }] };
4748
+ }
4749
+ case "delete_task": {
4750
+ const params = args;
4751
+ const success = deleteTask(params.project, params.task_slug);
4752
+ return { content: [{ type: "text", text: success ? `\u2713 Task '${params.task_slug}' deleted.` : `\u2717 Failed to delete '${params.task_slug}'.` }] };
4753
+ }
4754
+ case "search_tasks": {
4755
+ const params = args;
4756
+ const results = searchTasks(params.project, {
4757
+ keyword: params.keyword,
4758
+ status: params.status,
4759
+ agent: params.agent,
4760
+ since: params.since,
4761
+ limit: params.limit
4762
+ });
4763
+ return { content: [{ type: "text", text: JSON.stringify({ count: results.length, tasks: results }, null, 2) }] };
4764
+ }
4765
+ case "validate_phase": {
4766
+ const params = args;
4767
+ const result = validatePhase(params.project, params.task_slug, params.phase);
4768
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4769
+ }
4770
+ default:
4771
+ return null;
4772
+ }
4773
+ }
4774
+ var taskTools;
4775
+ var init_task = __esm({
4776
+ "src/mcp/handlers/tools/task.ts"() {
4777
+ "use strict";
4778
+ init_resources2();
4779
+ taskTools = [
4522
4780
  {
4523
- name: "search_tasks",
4524
- description: "Search across all tasks by keyword, status, agent phase, or date. Returns matching tasks sorted by relevance.",
4781
+ name: "list_tasks",
4782
+ description: "List all tasks for a project",
4525
4783
  inputSchema: {
4526
4784
  type: "object",
4527
- properties: {
4528
- project: { type: "string", description: "Name of the project" },
4529
- keyword: { type: "string", description: "Search in title/summary" },
4530
- status: { type: "string", description: "Filter by status (draft, in_progress, complete, etc.)" },
4531
- agent: { type: "string", description: "Filter by agent phase (research, planning, executor, documentation)" },
4532
- since: { type: "string", description: "ISO date - tasks updated after this date" },
4533
- limit: { type: "number", description: "Max results (default: 20)" }
4534
- },
4785
+ properties: { project: { type: "string", description: "Name of the project" } },
4535
4786
  required: ["project"]
4536
4787
  }
4537
4788
  },
4538
4789
  {
4539
- name: "validate_phase",
4540
- description: "Check if a task phase has all prerequisites complete. Returns validation result with missing items and suggestions.",
4790
+ name: "get_task",
4791
+ description: "Get details of a specific task",
4541
4792
  inputSchema: {
4542
4793
  type: "object",
4543
4794
  properties: {
4544
4795
  project: { type: "string", description: "Name of the project" },
4545
- task_slug: { type: "string", description: "The task slug" },
4546
- phase: { type: "string", enum: ["research", "planning", "execution", "documentation"], description: "Phase to validate" }
4796
+ task_slug: { type: "string", description: "The slug of the task" }
4547
4797
  },
4548
- required: ["project", "task_slug", "phase"]
4798
+ required: ["project", "task_slug"]
4549
4799
  }
4550
4800
  },
4551
4801
  {
4552
- name: "index_knowledge",
4553
- description: "Update the semantic search index for a specific project",
4802
+ name: "create_task",
4803
+ description: "Create a new task in the project",
4554
4804
  inputSchema: {
4555
4805
  type: "object",
4556
4806
  properties: {
4557
- project: { type: "string", description: "Name of the project to index" },
4558
- force: { type: "boolean", description: "Force re-indexing of all files" }
4807
+ project: { type: "string", description: "Name of the project" },
4808
+ task_slug: { type: "string", description: "The slug for the new task (kebab-case)" },
4809
+ title: { type: "string", description: "The title of the task" },
4810
+ summary: { type: "string", description: "Brief summary of the task" }
4559
4811
  },
4560
- required: ["project"]
4561
- }
4562
- },
4563
- {
4564
- name: "list_projects",
4565
- description: "List all projects exposed via MCP. Use these names for project-specific tools.",
4566
- inputSchema: { type: "object", properties: {} }
4567
- },
4568
- {
4569
- name: "get_project_context",
4570
- description: "Get the project context/architecture for a specific project",
4571
- inputSchema: {
4572
- type: "object",
4573
- properties: { project: { type: "string", description: "Name of the project to get context for" } },
4574
- required: ["project"]
4812
+ required: ["project", "task_slug"]
4575
4813
  }
4576
4814
  },
4577
4815
  {
4578
- name: "list_agents",
4579
- description: "List available agents (e.g. init, plan) and their arguments. Use this to discover which agent to call.",
4580
- inputSchema: { type: "object", properties: {} }
4581
- },
4582
- {
4583
- name: "get_agent_prompt",
4584
- description: 'Get the system prompt for a specific agent. Accepts agent Name (e.g. "RRCE Init") or ID (e.g. "init").',
4816
+ name: "update_task",
4817
+ description: "Update an existing task",
4585
4818
  inputSchema: {
4586
4819
  type: "object",
4587
4820
  properties: {
4588
- agent: { type: "string", description: "Name of the agent (e.g. init, plan, execute)" },
4589
- args: { type: "object", description: "Arguments for the agent prompt", additionalProperties: true }
4821
+ project: { type: "string", description: "Name of the project" },
4822
+ task_slug: { type: "string", description: "The slug of the task" },
4823
+ updates: { type: "object", description: "The fields to update in meta.json", additionalProperties: true }
4590
4824
  },
4591
- required: ["agent"]
4825
+ required: ["project", "task_slug", "updates"]
4592
4826
  }
4593
4827
  },
4594
4828
  {
4595
- name: "list_tasks",
4596
- description: "List all tasks for a project",
4829
+ name: "delete_task",
4830
+ description: "Delete a task from the project",
4597
4831
  inputSchema: {
4598
4832
  type: "object",
4599
- properties: { project: { type: "string", description: "Name of the project" } },
4600
- required: ["project"]
4833
+ properties: {
4834
+ project: { type: "string", description: "Name of the project" },
4835
+ task_slug: { type: "string", description: "The slug of the task to delete" }
4836
+ },
4837
+ required: ["project", "task_slug"]
4601
4838
  }
4602
4839
  },
4603
4840
  {
4604
- name: "get_task",
4605
- description: "Get details of a specific task",
4841
+ name: "search_tasks",
4842
+ description: "Search across all tasks by keyword, status, agent phase, or date. Returns matching tasks sorted by relevance.",
4606
4843
  inputSchema: {
4607
4844
  type: "object",
4608
4845
  properties: {
4609
4846
  project: { type: "string", description: "Name of the project" },
4610
- task_slug: { type: "string", description: "The slug of the task" }
4847
+ keyword: { type: "string", description: "Search in title/summary" },
4848
+ status: { type: "string", description: "Filter by status (draft, in_progress, complete, etc.)" },
4849
+ agent: { type: "string", description: "Filter by agent phase (research, planning, executor, documentation)" },
4850
+ since: { type: "string", description: "ISO date - tasks updated after this date" },
4851
+ limit: { type: "number", description: "Max results (default: 20)" }
4611
4852
  },
4612
- required: ["project", "task_slug"]
4853
+ required: ["project"]
4613
4854
  }
4614
4855
  },
4615
4856
  {
4616
- name: "create_task",
4617
- description: "Create a new task in the project",
4857
+ name: "validate_phase",
4858
+ description: "Check if a task phase has all prerequisites complete. Returns validation result with missing items and suggestions.",
4618
4859
  inputSchema: {
4619
4860
  type: "object",
4620
4861
  properties: {
4621
4862
  project: { type: "string", description: "Name of the project" },
4622
- task_slug: { type: "string", description: "The slug for the new task (kebab-case)" },
4623
- title: { type: "string", description: "The title of the task" },
4624
- summary: { type: "string", description: "Brief summary of the task" }
4863
+ task_slug: { type: "string", description: "The task slug" },
4864
+ phase: { type: "string", enum: ["research", "planning", "execution", "documentation"], description: "Phase to validate" }
4625
4865
  },
4626
- required: ["project", "task_slug"]
4866
+ required: ["project", "task_slug", "phase"]
4627
4867
  }
4628
- },
4868
+ }
4869
+ ];
4870
+ }
4871
+ });
4872
+
4873
+ // src/mcp/handlers/tools/session.ts
4874
+ async function handleSessionTool(name, args) {
4875
+ if (!args) return null;
4876
+ switch (name) {
4877
+ case "start_session": {
4878
+ const params = args;
4879
+ const result = startSession(params.project, params.task_slug, params.agent, params.phase);
4880
+ return { content: [{ type: "text", text: result.message }], isError: !result.success };
4881
+ }
4882
+ case "end_session": {
4883
+ const params = args;
4884
+ const result = endSession(params.project, params.task_slug);
4885
+ return { content: [{ type: "text", text: result.message }], isError: !result.success };
4886
+ }
4887
+ case "update_agent_todos": {
4888
+ const params = args;
4889
+ const result = updateAgentTodos(params.project, params.task_slug, params.phase, params.agent, params.items);
4890
+ return { content: [{ type: "text", text: result.message }], isError: !result.success };
4891
+ }
4892
+ default:
4893
+ return null;
4894
+ }
4895
+ }
4896
+ var sessionTools;
4897
+ var init_session = __esm({
4898
+ "src/mcp/handlers/tools/session.ts"() {
4899
+ "use strict";
4900
+ init_resources2();
4901
+ sessionTools = [
4629
4902
  {
4630
- name: "update_task",
4631
- description: "Update an existing task",
4903
+ name: "start_session",
4904
+ description: "Start an agent session for active task tracking. Call this when beginning work on a task phase.",
4632
4905
  inputSchema: {
4633
4906
  type: "object",
4634
4907
  properties: {
4635
4908
  project: { type: "string", description: "Name of the project" },
4636
4909
  task_slug: { type: "string", description: "The slug of the task" },
4637
- updates: { type: "object", description: "The fields to update in meta.json", additionalProperties: true }
4910
+ agent: { type: "string", description: "Agent type: research, planning, executor, or documentation" },
4911
+ phase: { type: "string", description: 'Current phase description (e.g., "clarification", "task breakdown")' }
4638
4912
  },
4639
- required: ["project", "task_slug", "updates"]
4913
+ required: ["project", "task_slug", "agent", "phase"]
4640
4914
  }
4641
4915
  },
4642
4916
  {
4643
- name: "delete_task",
4644
- description: "Delete a task from the project",
4917
+ name: "end_session",
4918
+ description: "End an agent session. Call this before emitting completion signal.",
4645
4919
  inputSchema: {
4646
4920
  type: "object",
4647
4921
  properties: {
4648
4922
  project: { type: "string", description: "Name of the project" },
4649
- task_slug: { type: "string", description: "The slug of the task to delete" }
4923
+ task_slug: { type: "string", description: "The slug of the task" }
4650
4924
  },
4651
4925
  required: ["project", "task_slug"]
4652
4926
  }
4653
4927
  },
4654
4928
  {
4655
- name: "start_session",
4656
- description: "Start an agent session for active task tracking. Call this when beginning work on a task phase.",
4929
+ name: "update_agent_todos",
4930
+ description: "Update the agent todo list for a task. Use this to track granular work items during a phase.",
4657
4931
  inputSchema: {
4658
4932
  type: "object",
4659
4933
  properties: {
4660
4934
  project: { type: "string", description: "Name of the project" },
4661
4935
  task_slug: { type: "string", description: "The slug of the task" },
4662
- agent: { type: "string", description: "Agent type: research, planning, executor, or documentation" },
4663
- phase: { type: "string", description: 'Current phase description (e.g., "clarification", "task breakdown")' }
4936
+ phase: { type: "string", description: "Current phase" },
4937
+ agent: { type: "string", description: "Agent type" },
4938
+ items: {
4939
+ type: "array",
4940
+ description: "Todo items array",
4941
+ items: {
4942
+ type: "object",
4943
+ properties: {
4944
+ id: { type: "string" },
4945
+ content: { type: "string" },
4946
+ status: { type: "string", enum: ["pending", "in_progress", "completed"] },
4947
+ priority: { type: "string", enum: ["high", "medium", "low"] }
4948
+ },
4949
+ required: ["id", "content", "status", "priority"]
4950
+ }
4951
+ }
4664
4952
  },
4665
- required: ["project", "task_slug", "agent", "phase"]
4953
+ required: ["project", "task_slug", "phase", "agent", "items"]
4954
+ }
4955
+ }
4956
+ ];
4957
+ }
4958
+ });
4959
+
4960
+ // src/mcp/prompts.ts
4961
+ import * as path26 from "path";
4962
+ import * as fs24 from "fs";
4963
+ function loadBaseProtocol2() {
4964
+ if (baseProtocolCache !== null) {
4965
+ return baseProtocolCache;
4966
+ }
4967
+ const basePath = path26.join(getAgentCorePromptsDir(), "_base.md");
4968
+ if (fs24.existsSync(basePath)) {
4969
+ const content = fs24.readFileSync(basePath, "utf-8");
4970
+ baseProtocolCache = content.replace(/^---[\s\S]*?---\n*/, "");
4971
+ return baseProtocolCache;
4972
+ }
4973
+ baseProtocolCache = "";
4974
+ return "";
4975
+ }
4976
+ function getAllPrompts() {
4977
+ const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
4978
+ return prompts.map((p) => {
4979
+ const args = [];
4980
+ if (p.frontmatter["required-args"]) {
4981
+ args.push(...p.frontmatter["required-args"].map((a) => ({
4982
+ name: a.name,
4983
+ description: a.prompt || a.name,
4984
+ required: true
4985
+ })));
4986
+ }
4987
+ if (p.frontmatter["optional-args"]) {
4988
+ args.push(...p.frontmatter["optional-args"].map((a) => ({
4989
+ name: a.name,
4990
+ description: a.prompt || a.name,
4991
+ required: false
4992
+ })));
4993
+ }
4994
+ const filename = p.filePath.split("/").pop() || "";
4995
+ const id = filename.replace(/\.md$/, "");
4996
+ return {
4997
+ id,
4998
+ name: p.frontmatter.name,
4999
+ description: p.frontmatter.description,
5000
+ arguments: args,
5001
+ content: p.content
5002
+ };
5003
+ });
5004
+ }
5005
+ function getPromptDef(name) {
5006
+ const all = getAllPrompts();
5007
+ const search = name.toLowerCase();
5008
+ return all.find(
5009
+ (p) => p.name === name || p.id === name || p.name.toLowerCase() === search || p.id.toLowerCase() === search
5010
+ );
5011
+ }
5012
+ function renderPromptWithContext(content, args) {
5013
+ const renderArgs = { ...args };
5014
+ let activeProject = detectActiveProject();
5015
+ if (!activeProject) {
5016
+ projectService.refresh();
5017
+ activeProject = detectActiveProject();
5018
+ }
5019
+ const DEFAULT_RRCE_HOME = getEffectiveGlobalPath();
5020
+ let resolvedRrceData = ".rrce-workflow/";
5021
+ let resolvedRrceHome = DEFAULT_RRCE_HOME;
5022
+ let resolvedWorkspaceRoot = process.cwd();
5023
+ let resolvedWorkspaceName = "current-project";
5024
+ if (activeProject) {
5025
+ resolvedRrceData = activeProject.dataPath;
5026
+ if (!resolvedRrceData.endsWith("/") && !resolvedRrceData.endsWith("\\")) {
5027
+ resolvedRrceData += "/";
5028
+ }
5029
+ resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
5030
+ resolvedWorkspaceName = activeProject.name;
5031
+ if (activeProject.source === "global") {
5032
+ const workspacesDir = path26.dirname(activeProject.dataPath);
5033
+ resolvedRrceHome = path26.dirname(workspacesDir);
5034
+ }
5035
+ } else {
5036
+ try {
5037
+ const workspaceRoot = detectWorkspaceRoot();
5038
+ const workspaceName = path26.basename(workspaceRoot);
5039
+ const globalWorkspacePath = path26.join(DEFAULT_RRCE_HOME, "workspaces", workspaceName);
5040
+ if (fs24.existsSync(globalWorkspacePath)) {
5041
+ resolvedRrceData = globalWorkspacePath;
5042
+ resolvedWorkspaceRoot = workspaceRoot;
5043
+ resolvedWorkspaceName = workspaceName;
5044
+ if (!resolvedRrceData.endsWith("/") && !resolvedRrceData.endsWith("\\")) {
5045
+ resolvedRrceData += "/";
4666
5046
  }
4667
- },
5047
+ }
5048
+ } catch (e) {
5049
+ }
5050
+ }
5051
+ if (!renderArgs["RRCE_DATA"]) renderArgs["RRCE_DATA"] = resolvedRrceData;
5052
+ if (!renderArgs["RRCE_HOME"]) renderArgs["RRCE_HOME"] = resolvedRrceHome;
5053
+ if (!renderArgs["WORKSPACE_ROOT"]) renderArgs["WORKSPACE_ROOT"] = resolvedWorkspaceRoot;
5054
+ if (!renderArgs["WORKSPACE_NAME"]) renderArgs["WORKSPACE_NAME"] = resolvedWorkspaceName;
5055
+ const agentContent = renderPrompt(content, renderArgs);
5056
+ const baseProtocol = loadBaseProtocol2();
5057
+ const rendered = baseProtocol ? `${baseProtocol}
5058
+ ${agentContent}` : agentContent;
5059
+ return {
5060
+ rendered,
5061
+ context: {
5062
+ RRCE_DATA: resolvedRrceData,
5063
+ RRCE_HOME: resolvedRrceHome,
5064
+ WORKSPACE_ROOT: resolvedWorkspaceRoot,
5065
+ WORKSPACE_NAME: resolvedWorkspaceName
5066
+ }
5067
+ };
5068
+ }
5069
+ function renderPrompt(content, args) {
5070
+ let rendered = content;
5071
+ for (const [key, val] of Object.entries(args)) {
5072
+ rendered = rendered.replace(new RegExp(`{{${key}}}`, "g"), val);
5073
+ }
5074
+ return rendered;
5075
+ }
5076
+ var baseProtocolCache;
5077
+ var init_prompts2 = __esm({
5078
+ "src/mcp/prompts.ts"() {
5079
+ "use strict";
5080
+ init_prompts();
5081
+ init_resources2();
5082
+ init_paths();
5083
+ init_detection_service();
5084
+ baseProtocolCache = null;
5085
+ }
5086
+ });
5087
+
5088
+ // src/mcp/handlers/tools/agent.ts
5089
+ async function handleAgentTool(name, args) {
5090
+ if (!args && name !== "list_agents") return null;
5091
+ switch (name) {
5092
+ case "list_agents": {
5093
+ const prompts = getAllPrompts();
5094
+ return {
5095
+ content: [{
5096
+ type: "text",
5097
+ text: JSON.stringify(prompts.map((p) => ({
5098
+ name: p.name,
5099
+ id: p.id,
5100
+ description: p.description,
5101
+ arguments: p.arguments
5102
+ })), null, 2) + "\n\nTip: Retrieve the prompt for an agent using `get_agent_prompt` with its name or ID."
5103
+ }]
5104
+ };
5105
+ }
5106
+ case "get_agent_prompt": {
5107
+ const params = args;
5108
+ const agentName = params.agent;
5109
+ const promptDef = getPromptDef(agentName);
5110
+ if (!promptDef) {
5111
+ const available = getAllPrompts().map((p) => `${p.name} (id: ${p.id})`).join(", ");
5112
+ throw new Error(`Agent not found: ${agentName}. Available agents: ${available}`);
5113
+ }
5114
+ const renderArgs = params.args || {};
5115
+ const stringArgs = {};
5116
+ for (const [key, val] of Object.entries(renderArgs)) {
5117
+ stringArgs[key] = String(val);
5118
+ }
5119
+ const { rendered } = renderPromptWithContext(promptDef.content, stringArgs);
5120
+ const contextPreamble = getContextPreamble();
5121
+ return { content: [{ type: "text", text: contextPreamble + rendered }] };
5122
+ }
5123
+ default:
5124
+ return null;
5125
+ }
5126
+ }
5127
+ var agentTools;
5128
+ var init_agent = __esm({
5129
+ "src/mcp/handlers/tools/agent.ts"() {
5130
+ "use strict";
5131
+ init_resources2();
5132
+ init_prompts2();
5133
+ agentTools = [
4668
5134
  {
4669
- name: "end_session",
4670
- description: "End an agent session. Call this before emitting completion signal.",
4671
- inputSchema: {
4672
- type: "object",
4673
- properties: {
4674
- project: { type: "string", description: "Name of the project" },
4675
- task_slug: { type: "string", description: "The slug of the task" }
4676
- },
4677
- required: ["project", "task_slug"]
4678
- }
5135
+ name: "list_agents",
5136
+ description: "List available agents (e.g. init, plan) and their arguments. Use this to discover which agent to call.",
5137
+ inputSchema: { type: "object", properties: {} }
4679
5138
  },
4680
5139
  {
4681
- name: "update_agent_todos",
4682
- description: "Update the agent todo list for a task. Use this to track granular work items during a phase.",
5140
+ name: "get_agent_prompt",
5141
+ description: 'Get the system prompt for a specific agent. Accepts agent Name (e.g. "RRCE Init") or ID (e.g. "init").',
4683
5142
  inputSchema: {
4684
5143
  type: "object",
4685
5144
  properties: {
4686
- project: { type: "string", description: "Name of the project" },
4687
- task_slug: { type: "string", description: "The slug of the task" },
4688
- phase: { type: "string", description: "Current phase" },
4689
- agent: { type: "string", description: "Agent type" },
4690
- items: {
4691
- type: "array",
4692
- description: "Todo items array",
4693
- items: {
4694
- type: "object",
4695
- properties: {
4696
- id: { type: "string" },
4697
- content: { type: "string" },
4698
- status: { type: "string", enum: ["pending", "in_progress", "completed"] },
4699
- priority: { type: "string", enum: ["high", "medium", "low"] }
4700
- },
4701
- required: ["id", "content", "status", "priority"]
4702
- }
4703
- }
5145
+ agent: { type: "string", description: "Name of the agent (e.g. init, plan, execute)" },
5146
+ args: { type: "object", description: "Arguments for the agent prompt", additionalProperties: true }
4704
5147
  },
4705
- required: ["project", "task_slug", "phase", "agent", "items"]
5148
+ required: ["agent"]
4706
5149
  }
4707
5150
  }
4708
5151
  ];
5152
+ }
5153
+ });
5154
+
5155
+ // src/mcp/handlers/tools.ts
5156
+ import "@modelcontextprotocol/sdk/server/index.js";
5157
+ import {
5158
+ ListToolsRequestSchema,
5159
+ CallToolRequestSchema
5160
+ } from "@modelcontextprotocol/sdk/types.js";
5161
+ function registerToolHandlers(server) {
5162
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
5163
+ const tools = [
5164
+ ...projectTools,
5165
+ ...searchTools,
5166
+ ...taskTools,
5167
+ ...sessionTools,
5168
+ ...agentTools
5169
+ ];
4709
5170
  const projects = getExposedProjects();
4710
5171
  if (projects.length === 0) {
4711
5172
  tools.push({
@@ -4720,221 +5181,17 @@ function registerToolHandlers(server) {
4720
5181
  const { name, arguments: args } = request.params;
4721
5182
  logger.info(`Calling tool: ${name}`, args);
4722
5183
  try {
4723
- switch (name) {
4724
- case "resolve_path": {
4725
- const params = args;
4726
- const result = resolveProjectPaths(params.project, params.path);
4727
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4728
- }
4729
- case "search_knowledge": {
4730
- const params = args;
4731
- const result = await searchKnowledge(params.query, params.project, {
4732
- max_tokens: params.max_tokens,
4733
- min_score: params.min_score
4734
- });
4735
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4736
- }
4737
- case "search_code": {
4738
- const params = args;
4739
- const result = await searchCode(params.query, params.project, params.limit, {
4740
- max_tokens: params.max_tokens,
4741
- min_score: params.min_score
4742
- });
4743
- if (result.results.length === 0) {
4744
- return {
4745
- content: [{
4746
- type: "text",
4747
- text: "No code matches found. The code index may be empty or semantic search is not enabled.\nRun `index_knowledge` first to build the code index."
4748
- }]
4749
- };
4750
- }
4751
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4752
- }
4753
- case "find_related_files": {
4754
- const params = args;
4755
- const result = await findRelatedFiles2(params.file, params.project, {
4756
- includeImports: params.include_imports,
4757
- includeImportedBy: params.include_imported_by,
4758
- depth: params.depth
4759
- });
4760
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4761
- }
4762
- case "search_symbols": {
4763
- const params = args;
4764
- const result = await searchSymbols2(params.name, params.project, {
4765
- type: params.type,
4766
- fuzzy: params.fuzzy,
4767
- limit: params.limit
4768
- });
4769
- if (!result.success) {
4770
- return { content: [{ type: "text", text: result.message || "Search failed" }], isError: true };
4771
- }
4772
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4773
- }
4774
- case "get_file_summary": {
4775
- const params = args;
4776
- const result = await getFileSummary(params.file, params.project);
4777
- if (!result.success) {
4778
- return { content: [{ type: "text", text: result.message || "Failed to get file summary" }], isError: true };
4779
- }
4780
- return { content: [{ type: "text", text: JSON.stringify(result.summary, null, 2) }] };
4781
- }
4782
- case "get_context_bundle": {
4783
- const params = args;
4784
- const result = await getContextBundle(params.query, params.project, {
4785
- task_slug: params.task_slug,
4786
- max_tokens: params.max_tokens,
4787
- include: params.include
4788
- });
4789
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4790
- }
4791
- case "index_knowledge": {
4792
- const params = args;
4793
- const result = await indexKnowledge(params.project, params.force);
4794
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4795
- }
4796
- case "list_projects": {
4797
- const projects = getExposedProjects();
4798
- const list = projects.map((p) => ({ name: p.name, source: p.source, path: p.path }));
4799
- return {
4800
- content: [{
4801
- type: "text",
4802
- text: JSON.stringify(list, null, 2) + "\n\nTip: Use these project names for tools like `get_project_context` or `index_knowledge`."
4803
- }]
4804
- };
4805
- }
4806
- case "get_project_context": {
4807
- const context = getProjectContext(args.project);
4808
- if (!context) {
4809
- const projects = getExposedProjects().map((p) => p.name).join(", ");
4810
- const msg = `No project context found for "${args.project}".
4811
- Available projects: ${projects}`;
4812
- logger.warn(msg);
4813
- return { content: [{ type: "text", text: msg }], isError: true };
4814
- }
4815
- return { content: [{ type: "text", text: context }] };
4816
- }
4817
- case "list_agents": {
4818
- const prompts = getAllPrompts();
4819
- return {
4820
- content: [{
4821
- type: "text",
4822
- text: JSON.stringify(prompts.map((p) => ({
4823
- name: p.name,
4824
- id: p.id,
4825
- description: p.description,
4826
- arguments: p.arguments
4827
- })), null, 2) + "\n\nTip: Retrieve the prompt for an agent using `get_agent_prompt` with its name or ID."
4828
- }]
4829
- };
4830
- }
4831
- case "get_agent_prompt": {
4832
- const params = args;
4833
- const agentName = params.agent;
4834
- const promptDef = getPromptDef(agentName);
4835
- if (!promptDef) {
4836
- const available = getAllPrompts().map((p) => `${p.name} (id: ${p.id})`).join(", ");
4837
- throw new Error(`Agent not found: ${agentName}. Available agents: ${available}`);
4838
- }
4839
- const renderArgs = params.args || {};
4840
- const stringArgs = {};
4841
- for (const [key, val] of Object.entries(renderArgs)) {
4842
- stringArgs[key] = String(val);
4843
- }
4844
- const { rendered } = renderPromptWithContext(promptDef.content, stringArgs);
4845
- const contextPreamble = getContextPreamble();
4846
- return { content: [{ type: "text", text: contextPreamble + rendered }] };
4847
- }
4848
- case "list_tasks": {
4849
- const params = args;
4850
- const tasks = getProjectTasks(params.project);
4851
- return { content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }] };
4852
- }
4853
- case "get_task": {
4854
- const params = args;
4855
- const task = getTask(params.project, params.task_slug);
4856
- if (!task) {
4857
- return { content: [{ type: "text", text: `Task '${params.task_slug}' not found in project '${params.project}'.` }], isError: true };
4858
- }
4859
- return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
4860
- }
4861
- case "create_task": {
4862
- const params = args;
4863
- const taskData = {
4864
- title: params.title || params.task_slug,
4865
- summary: params.summary || ""
4866
- };
4867
- const task = await createTask(params.project, params.task_slug, taskData);
4868
- return { content: [{ type: "text", text: `\u2713 Task '${params.task_slug}' created. meta.json saved.
4869
- ${JSON.stringify(task, null, 2)}` }] };
4870
- }
4871
- case "update_task": {
4872
- const params = args;
4873
- const task = await updateTask(params.project, params.task_slug, params.updates);
4874
- return { content: [{ type: "text", text: `\u2713 Task '${params.task_slug}' updated. meta.json saved.
4875
- ${JSON.stringify(task, null, 2)}` }] };
4876
- }
4877
- case "delete_task": {
4878
- const params = args;
4879
- const success = deleteTask(params.project, params.task_slug);
4880
- return { content: [{ type: "text", text: success ? `\u2713 Task '${params.task_slug}' deleted.` : `\u2717 Failed to delete '${params.task_slug}'.` }] };
4881
- }
4882
- case "start_session": {
4883
- const params = args;
4884
- const result = startSession(params.project, params.task_slug, params.agent, params.phase);
4885
- return { content: [{ type: "text", text: result.message }], isError: !result.success };
4886
- }
4887
- case "end_session": {
4888
- const params = args;
4889
- const result = endSession(params.project, params.task_slug);
4890
- return { content: [{ type: "text", text: result.message }], isError: !result.success };
4891
- }
4892
- case "update_agent_todos": {
4893
- const params = args;
4894
- const result = updateAgentTodos(params.project, params.task_slug, params.phase, params.agent, params.items);
4895
- return { content: [{ type: "text", text: result.message }], isError: !result.success };
4896
- }
4897
- case "prefetch_task_context": {
4898
- const params = args;
4899
- const result = await prefetchTaskContext(params.project, params.task_slug, {
4900
- max_tokens: params.max_tokens
4901
- });
4902
- if (!result.success) {
4903
- return { content: [{ type: "text", text: result.message || "Failed to prefetch task context" }], isError: true };
4904
- }
4905
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4906
- }
4907
- case "search_tasks": {
4908
- const params = args;
4909
- const results = searchTasks(params.project, {
4910
- keyword: params.keyword,
4911
- status: params.status,
4912
- agent: params.agent,
4913
- since: params.since,
4914
- limit: params.limit
4915
- });
4916
- return { content: [{ type: "text", text: JSON.stringify({ count: results.length, tasks: results }, null, 2) }] };
4917
- }
4918
- case "validate_phase": {
4919
- const params = args;
4920
- const result = validatePhase(params.project, params.task_slug, params.phase);
4921
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4922
- }
4923
- case "help_setup": {
4924
- const msg = `
4925
- RRCE MCP Server is running, but no projects are configured/exposed.
4926
-
4927
- To fix this:
4928
- 1. Open a terminal.
4929
- 2. Run: npx rrce-workflow mcp configure
4930
- 3. Select the projects you want to expose to the AI.
4931
- 4. Restart the MCP server (or it may pick up changes automatically).
4932
- `;
4933
- return { content: [{ type: "text", text: msg }] };
4934
- }
4935
- default:
4936
- throw new Error(`Unknown tool: ${name}`);
4937
- }
5184
+ const projectResult = await handleProjectTool(name, args);
5185
+ if (projectResult) return projectResult;
5186
+ const searchResult = await handleSearchTool(name, args);
5187
+ if (searchResult) return searchResult;
5188
+ const taskResult = await handleTaskTool(name, args);
5189
+ if (taskResult) return taskResult;
5190
+ const sessionResult = await handleSessionTool(name, args);
5191
+ if (sessionResult) return sessionResult;
5192
+ const agentResult = await handleAgentTool(name, args);
5193
+ if (agentResult) return agentResult;
5194
+ throw new Error(`Unknown tool: ${name}`);
4938
5195
  } catch (error) {
4939
5196
  logger.error(`Tool execution failed: ${name}`, error);
4940
5197
  throw error;
@@ -4946,7 +5203,11 @@ var init_tools = __esm({
4946
5203
  "use strict";
4947
5204
  init_logger();
4948
5205
  init_resources2();
4949
- init_prompts2();
5206
+ init_project();
5207
+ init_search2();
5208
+ init_task();
5209
+ init_session();
5210
+ init_agent();
4950
5211
  }
4951
5212
  });
4952
5213
 
@@ -5172,8 +5433,8 @@ Hidden projects: ${projects.length - exposedCount}`,
5172
5433
  }
5173
5434
  async function handleConfigureGlobalPath() {
5174
5435
  const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
5175
- const fs33 = await import("fs");
5176
- const path32 = await import("path");
5436
+ const fs34 = await import("fs");
5437
+ const path33 = await import("path");
5177
5438
  note3(
5178
5439
  `MCP Hub requires a ${pc5.bold("global storage path")} to store its configuration
5179
5440
  and coordinate across projects.
@@ -5187,8 +5448,8 @@ locally in each project. MCP needs a central location.`,
5187
5448
  return false;
5188
5449
  }
5189
5450
  try {
5190
- if (!fs33.existsSync(resolvedPath)) {
5191
- fs33.mkdirSync(resolvedPath, { recursive: true });
5451
+ if (!fs34.existsSync(resolvedPath)) {
5452
+ fs34.mkdirSync(resolvedPath, { recursive: true });
5192
5453
  }
5193
5454
  const config = loadMCPConfig();
5194
5455
  saveMCPConfig(config);
@@ -5196,7 +5457,7 @@ locally in each project. MCP needs a central location.`,
5196
5457
  `${pc5.green("\u2713")} Global path configured: ${pc5.cyan(resolvedPath)}
5197
5458
 
5198
5459
  MCP config will be stored at:
5199
- ${path32.join(resolvedPath, "mcp.yaml")}`,
5460
+ ${path33.join(resolvedPath, "mcp.yaml")}`,
5200
5461
  "Configuration Saved"
5201
5462
  );
5202
5463
  return true;
@@ -5292,105 +5553,6 @@ var init_Header = __esm({
5292
5553
  }
5293
5554
  });
5294
5555
 
5295
- // src/lib/drift-service.ts
5296
- import * as fs23 from "fs";
5297
- import * as path25 from "path";
5298
- import * as crypto2 from "crypto";
5299
- var DriftService;
5300
- var init_drift_service = __esm({
5301
- "src/lib/drift-service.ts"() {
5302
- "use strict";
5303
- DriftService = class {
5304
- static CHECKSUM_FILENAME = ".rrce-checksums.json";
5305
- static calculateHash(filePath) {
5306
- const content = fs23.readFileSync(filePath);
5307
- return crypto2.createHash("md5").update(content).digest("hex");
5308
- }
5309
- static getManifestPath(projectPath) {
5310
- return path25.join(projectPath, this.CHECKSUM_FILENAME);
5311
- }
5312
- static loadManifest(projectPath) {
5313
- const manifestPath = this.getManifestPath(projectPath);
5314
- if (!fs23.existsSync(manifestPath)) {
5315
- return {};
5316
- }
5317
- try {
5318
- return JSON.parse(fs23.readFileSync(manifestPath, "utf8"));
5319
- } catch (e) {
5320
- return {};
5321
- }
5322
- }
5323
- static saveManifest(projectPath, manifest) {
5324
- const manifestPath = this.getManifestPath(projectPath);
5325
- fs23.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
5326
- }
5327
- /**
5328
- * Generates a manifest for the current state of files in the project
5329
- */
5330
- static generateManifest(projectPath, files) {
5331
- const manifest = {};
5332
- for (const file of files) {
5333
- const fullPath = path25.join(projectPath, file);
5334
- if (fs23.existsSync(fullPath)) {
5335
- const stats = fs23.statSync(fullPath);
5336
- manifest[file] = {
5337
- hash: this.calculateHash(fullPath),
5338
- mtime: stats.mtimeMs
5339
- };
5340
- }
5341
- }
5342
- return manifest;
5343
- }
5344
- /**
5345
- * Compares current files against the manifest to detect modifications
5346
- */
5347
- static detectModifiedFiles(projectPath) {
5348
- const manifest = this.loadManifest(projectPath);
5349
- const modifiedFiles = [];
5350
- for (const [relPath, entry] of Object.entries(manifest)) {
5351
- const fullPath = path25.join(projectPath, relPath);
5352
- if (!fs23.existsSync(fullPath)) {
5353
- continue;
5354
- }
5355
- const stats = fs23.statSync(fullPath);
5356
- if (stats.mtimeMs === entry.mtime) {
5357
- continue;
5358
- }
5359
- const currentHash = this.calculateHash(fullPath);
5360
- if (currentHash !== entry.hash) {
5361
- modifiedFiles.push(relPath);
5362
- }
5363
- }
5364
- return modifiedFiles;
5365
- }
5366
- /**
5367
- * Full drift check: version + modifications
5368
- */
5369
- static checkDrift(projectPath, currentVersion, runningVersion) {
5370
- const modifiedFiles = this.detectModifiedFiles(projectPath);
5371
- let type = "none";
5372
- let hasDrift = false;
5373
- if (currentVersion !== runningVersion) {
5374
- hasDrift = true;
5375
- type = "version";
5376
- } else if (modifiedFiles.length > 0) {
5377
- hasDrift = true;
5378
- type = "modified";
5379
- }
5380
- return {
5381
- hasDrift,
5382
- type,
5383
- modifiedFiles,
5384
- version: {
5385
- current: currentVersion || "0.0.0",
5386
- running: runningVersion
5387
- }
5388
- };
5389
- }
5390
- };
5391
- }
5392
- });
5393
-
5394
5556
  // src/mcp/ui/ConfigContext.tsx
5395
5557
  var ConfigContext_exports = {};
5396
5558
  __export(ConfigContext_exports, {
@@ -5399,15 +5561,15 @@ __export(ConfigContext_exports, {
5399
5561
  useConfig: () => useConfig
5400
5562
  });
5401
5563
  import { createContext, useContext, useState, useCallback, useMemo, useEffect } from "react";
5402
- import * as fs24 from "fs";
5403
- import * as path26 from "path";
5564
+ import * as fs25 from "fs";
5565
+ import * as path27 from "path";
5404
5566
  import { jsx as jsx2 } from "react/jsx-runtime";
5405
5567
  function getPackageVersion() {
5406
5568
  try {
5407
5569
  const agentCoreDir = getAgentCoreDir();
5408
- const packageJsonPath = path26.join(path26.dirname(agentCoreDir), "package.json");
5409
- if (fs24.existsSync(packageJsonPath)) {
5410
- return JSON.parse(fs24.readFileSync(packageJsonPath, "utf8")).version;
5570
+ const packageJsonPath = path27.join(path27.dirname(agentCoreDir), "package.json");
5571
+ if (fs25.existsSync(packageJsonPath)) {
5572
+ return JSON.parse(fs25.readFileSync(packageJsonPath, "utf8")).version;
5411
5573
  }
5412
5574
  } catch (e) {
5413
5575
  }
@@ -5474,16 +5636,16 @@ var init_ConfigContext = __esm({
5474
5636
  });
5475
5637
 
5476
5638
  // src/mcp/ui/lib/tasks-fs.ts
5477
- import * as fs25 from "fs";
5478
- import * as path27 from "path";
5639
+ import * as fs26 from "fs";
5640
+ import * as path28 from "path";
5479
5641
  function readSession(project, taskSlug) {
5480
5642
  const rrceData = getProjectRRCEData(project);
5481
- const sessionPath = path27.join(rrceData, "tasks", taskSlug, "session.json");
5482
- if (!fs25.existsSync(sessionPath)) {
5643
+ const sessionPath = path28.join(rrceData, "tasks", taskSlug, "session.json");
5644
+ if (!fs26.existsSync(sessionPath)) {
5483
5645
  return null;
5484
5646
  }
5485
5647
  try {
5486
- const raw = fs25.readFileSync(sessionPath, "utf-8");
5648
+ const raw = fs26.readFileSync(sessionPath, "utf-8");
5487
5649
  return JSON.parse(raw);
5488
5650
  } catch {
5489
5651
  return null;
@@ -5496,12 +5658,12 @@ function isSessionStale(session, thresholdMs = SESSION_STALE_THRESHOLD_MS) {
5496
5658
  }
5497
5659
  function readAgentTodos(project, taskSlug) {
5498
5660
  const rrceData = getProjectRRCEData(project);
5499
- const todosPath = path27.join(rrceData, "tasks", taskSlug, "agent-todos.json");
5500
- if (!fs25.existsSync(todosPath)) {
5661
+ const todosPath = path28.join(rrceData, "tasks", taskSlug, "agent-todos.json");
5662
+ if (!fs26.existsSync(todosPath)) {
5501
5663
  return null;
5502
5664
  }
5503
5665
  try {
5504
- const raw = fs25.readFileSync(todosPath, "utf-8");
5666
+ const raw = fs26.readFileSync(todosPath, "utf-8");
5505
5667
  return JSON.parse(raw);
5506
5668
  } catch {
5507
5669
  return null;
@@ -5514,8 +5676,8 @@ function detectStorageModeFromConfig(workspaceRoot) {
5514
5676
  if (configPath.startsWith(rrceHome)) {
5515
5677
  return "global";
5516
5678
  }
5517
- if (fs25.existsSync(configPath)) {
5518
- const content = fs25.readFileSync(configPath, "utf-8");
5679
+ if (fs26.existsSync(configPath)) {
5680
+ const content = fs26.readFileSync(configPath, "utf-8");
5519
5681
  if (content.includes("mode: workspace")) return "workspace";
5520
5682
  if (content.includes("mode: global")) return "global";
5521
5683
  }
@@ -5525,7 +5687,7 @@ function detectStorageModeFromConfig(workspaceRoot) {
5525
5687
  }
5526
5688
  function getEffectiveGlobalBase() {
5527
5689
  const dummy = resolveDataPath("global", "__rrce_dummy__", "");
5528
- return path27.dirname(path27.dirname(dummy));
5690
+ return path28.dirname(path28.dirname(dummy));
5529
5691
  }
5530
5692
  function getProjectRRCEData(project) {
5531
5693
  const workspaceRoot = project.sourcePath || project.path;
@@ -5534,19 +5696,19 @@ function getProjectRRCEData(project) {
5534
5696
  }
5535
5697
  function listProjectTasks(project) {
5536
5698
  const rrceData = getProjectRRCEData(project);
5537
- const tasksPath = path27.join(rrceData, "tasks");
5538
- if (!fs25.existsSync(tasksPath)) {
5699
+ const tasksPath = path28.join(rrceData, "tasks");
5700
+ if (!fs26.existsSync(tasksPath)) {
5539
5701
  return { projectName: project.name, tasksPath, tasks: [] };
5540
5702
  }
5541
5703
  const tasks = [];
5542
5704
  try {
5543
- const entries = fs25.readdirSync(tasksPath, { withFileTypes: true });
5705
+ const entries = fs26.readdirSync(tasksPath, { withFileTypes: true });
5544
5706
  for (const entry of entries) {
5545
5707
  if (!entry.isDirectory()) continue;
5546
- const metaPath = path27.join(tasksPath, entry.name, "meta.json");
5547
- if (!fs25.existsSync(metaPath)) continue;
5708
+ const metaPath = path28.join(tasksPath, entry.name, "meta.json");
5709
+ if (!fs26.existsSync(metaPath)) continue;
5548
5710
  try {
5549
- const raw = fs25.readFileSync(metaPath, "utf-8");
5711
+ const raw = fs26.readFileSync(metaPath, "utf-8");
5550
5712
  const meta = JSON.parse(raw);
5551
5713
  if (!meta.task_slug) meta.task_slug = entry.name;
5552
5714
  tasks.push(meta);
@@ -5565,18 +5727,18 @@ function listProjectTasks(project) {
5565
5727
  }
5566
5728
  function updateTaskStatus(project, taskSlug, status) {
5567
5729
  const rrceData = getProjectRRCEData(project);
5568
- const metaPath = path27.join(rrceData, "tasks", taskSlug, "meta.json");
5569
- if (!fs25.existsSync(metaPath)) {
5730
+ const metaPath = path28.join(rrceData, "tasks", taskSlug, "meta.json");
5731
+ if (!fs26.existsSync(metaPath)) {
5570
5732
  return { ok: false, error: `meta.json not found for task '${taskSlug}'` };
5571
5733
  }
5572
5734
  try {
5573
- const meta = JSON.parse(fs25.readFileSync(metaPath, "utf-8"));
5735
+ const meta = JSON.parse(fs26.readFileSync(metaPath, "utf-8"));
5574
5736
  const next = {
5575
5737
  ...meta,
5576
5738
  status,
5577
5739
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
5578
5740
  };
5579
- fs25.writeFileSync(metaPath, JSON.stringify(next, null, 2));
5741
+ fs26.writeFileSync(metaPath, JSON.stringify(next, null, 2));
5580
5742
  return { ok: true, meta: next };
5581
5743
  } catch (e) {
5582
5744
  return { ok: false, error: String(e) };
@@ -5934,31 +6096,54 @@ var init_project_utils = __esm({
5934
6096
  }
5935
6097
  });
5936
6098
 
5937
- // src/mcp/ui/ProjectsView.tsx
5938
- import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
5939
- import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
5940
- import * as fs26 from "fs";
5941
- import * as path28 from "path";
6099
+ // src/mcp/ui/components/ProjectViews.tsx
6100
+ import "react";
6101
+ import { Box as Box4, Text as Text4 } from "ink";
5942
6102
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
6103
+ var ProjectsHeader, ProjectsFooter;
6104
+ var init_ProjectViews = __esm({
6105
+ "src/mcp/ui/components/ProjectViews.tsx"() {
6106
+ "use strict";
6107
+ ProjectsHeader = ({ autoExpose }) => /* @__PURE__ */ jsxs3(Box4, { paddingX: 1, justifyContent: "space-between", borderBottom: true, children: [
6108
+ /* @__PURE__ */ jsxs3(Box4, { children: [
6109
+ /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: "Projects" }),
6110
+ /* @__PURE__ */ jsx5(Text4, { color: "dim", children: " \u2502 " }),
6111
+ /* @__PURE__ */ jsxs3(Text4, { color: autoExpose ? "green" : "red", children: [
6112
+ "Auto-expose: ",
6113
+ autoExpose ? "ON" : "OFF"
6114
+ ] })
6115
+ ] }),
6116
+ /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "v0.3.14" })
6117
+ ] });
6118
+ ProjectsFooter = () => /* @__PURE__ */ jsxs3(Box4, { paddingX: 1, justifyContent: "space-between", borderTop: true, children: [
6119
+ /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Space:Select Enter:Save a:Toggle Auto u:Refresh Drift" }),
6120
+ /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Use 'rrce-workflow wizard' for advanced config" })
6121
+ ] });
6122
+ }
6123
+ });
6124
+
6125
+ // src/mcp/ui/lib/projects.ts
6126
+ import * as fs27 from "fs";
6127
+ import * as path29 from "path";
5943
6128
  function getIndexStats(project) {
5944
6129
  const stats = { knowledgeCount: 0, codeCount: 0, lastIndexed: null };
5945
6130
  try {
5946
6131
  const knowledgePath = project.knowledgePath;
5947
6132
  if (knowledgePath) {
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);
6133
+ const embPath = path29.join(knowledgePath, "embeddings.json");
6134
+ const codeEmbPath = path29.join(knowledgePath, "code-embeddings.json");
6135
+ if (fs27.existsSync(embPath)) {
6136
+ const stat = fs27.statSync(embPath);
5952
6137
  stats.lastIndexed = stat.mtime.toISOString();
5953
6138
  try {
5954
- const data = JSON.parse(fs26.readFileSync(embPath, "utf-8"));
6139
+ const data = JSON.parse(fs27.readFileSync(embPath, "utf-8"));
5955
6140
  stats.knowledgeCount = Array.isArray(data) ? data.length : Object.keys(data).length;
5956
6141
  } catch {
5957
6142
  }
5958
6143
  }
5959
- if (fs26.existsSync(codeEmbPath)) {
6144
+ if (fs27.existsSync(codeEmbPath)) {
5960
6145
  try {
5961
- const data = JSON.parse(fs26.readFileSync(codeEmbPath, "utf-8"));
6146
+ const data = JSON.parse(fs27.readFileSync(codeEmbPath, "utf-8"));
5962
6147
  stats.codeCount = Array.isArray(data) ? data.length : Object.keys(data).length;
5963
6148
  } catch {
5964
6149
  }
@@ -5968,6 +6153,16 @@ function getIndexStats(project) {
5968
6153
  }
5969
6154
  return stats;
5970
6155
  }
6156
+ var init_projects2 = __esm({
6157
+ "src/mcp/ui/lib/projects.ts"() {
6158
+ "use strict";
6159
+ }
6160
+ });
6161
+
6162
+ // src/mcp/ui/ProjectsView.tsx
6163
+ import { useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
6164
+ import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
6165
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
5971
6166
  var ProjectsView;
5972
6167
  var init_ProjectsView = __esm({
5973
6168
  "src/mcp/ui/ProjectsView.tsx"() {
@@ -5979,6 +6174,8 @@ var init_ProjectsView = __esm({
5979
6174
  init_config_utils();
5980
6175
  init_project_utils();
5981
6176
  init_ui_helpers();
6177
+ init_ProjectViews();
6178
+ init_projects2();
5982
6179
  ProjectsView = ({ config: initialConfig, projects: allProjects, onConfigChange, workspacePath }) => {
5983
6180
  const { driftReports, checkAllDrift } = useConfig();
5984
6181
  const [config, setConfig] = useState3(initialConfig);
@@ -6084,20 +6281,10 @@ ${statsRow}` : label;
6084
6281
  setConfig(newConfig);
6085
6282
  onConfigChange?.();
6086
6283
  };
6087
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", borderStyle: "round", borderColor: "white", flexGrow: 1, children: [
6088
- /* @__PURE__ */ jsxs3(Box4, { paddingX: 1, justifyContent: "space-between", borderBottom: true, children: [
6089
- /* @__PURE__ */ jsxs3(Box4, { children: [
6090
- /* @__PURE__ */ jsx5(Text4, { bold: true, color: "cyan", children: "Projects" }),
6091
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: " \u2502 " }),
6092
- /* @__PURE__ */ jsxs3(Text4, { color: config.defaults.includeNew ? "green" : "red", children: [
6093
- "Auto-expose: ",
6094
- config.defaults.includeNew ? "ON" : "OFF"
6095
- ] })
6096
- ] }),
6097
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "v0.3.14" })
6098
- ] }),
6099
- /* @__PURE__ */ jsx5(Box4, { marginTop: 1, paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Manage which projects are exposed to the MCP server." }) }),
6100
- /* @__PURE__ */ jsx5(Box4, { marginTop: 1, paddingX: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx5(
6284
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "white", flexGrow: 1, children: [
6285
+ /* @__PURE__ */ jsx6(ProjectsHeader, { autoExpose: config.defaults.includeNew }),
6286
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, paddingX: 1, children: /* @__PURE__ */ jsx6(Text5, { color: "dim", children: "Manage which projects are exposed to the MCP server." }) }),
6287
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, paddingX: 1, flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx6(
6101
6288
  SimpleSelect,
6102
6289
  {
6103
6290
  message: "",
@@ -6112,111 +6299,7 @@ ${statsRow}` : label;
6112
6299
  },
6113
6300
  JSON.stringify(initialSelected) + config.defaults.includeNew + JSON.stringify(indexingStats)
6114
6301
  ) }),
6115
- /* @__PURE__ */ jsxs3(Box4, { paddingX: 1, justifyContent: "space-between", borderTop: true, children: [
6116
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Space:Select Enter:Save a:Toggle Auto u:Refresh Drift" }),
6117
- /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Use 'rrce-workflow wizard' for advanced config" })
6118
- ] })
6119
- ] });
6120
- };
6121
- }
6122
- });
6123
-
6124
- // src/mcp/ui/components/TaskRow.tsx
6125
- import "react";
6126
- import { Box as Box5, Text as Text5 } from "ink";
6127
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
6128
- function getActiveAgent(task) {
6129
- if (!task.agents) return null;
6130
- for (const [agent, info] of Object.entries(task.agents)) {
6131
- if (info?.status === "in_progress") {
6132
- return { agent, status: "in_progress" };
6133
- }
6134
- }
6135
- const agentOrder = ["documentation", "executor", "planning", "research"];
6136
- for (const agent of agentOrder) {
6137
- if (task.agents[agent]?.status === "complete") {
6138
- return { agent, status: "complete" };
6139
- }
6140
- }
6141
- return null;
6142
- }
6143
- var TaskRow;
6144
- var init_TaskRow = __esm({
6145
- "src/mcp/ui/components/TaskRow.tsx"() {
6146
- "use strict";
6147
- init_ui_helpers();
6148
- init_project_utils();
6149
- TaskRow = ({
6150
- row,
6151
- isSelected,
6152
- isExpanded,
6153
- taskCount,
6154
- hasDrift,
6155
- isCurrentProject = false,
6156
- isLastTask = false
6157
- }) => {
6158
- if (row.kind === "project") {
6159
- const projectColor = isSelected ? "cyan" : isCurrentProject ? "yellow" : "white";
6160
- const isBold = isSelected || isCurrentProject;
6161
- return /* @__PURE__ */ jsxs4(Box5, { children: [
6162
- /* @__PURE__ */ jsx6(Text5, { color: isSelected ? "cyan" : "dim", children: isSelected ? "\u25B8 " : " " }),
6163
- /* @__PURE__ */ jsxs4(Text5, { bold: isBold, color: projectColor, children: [
6164
- getFolderIcon(isExpanded),
6165
- " ",
6166
- formatProjectLabel(row.project)
6167
- ] }),
6168
- isCurrentProject && /* @__PURE__ */ jsx6(Text5, { color: "yellow", dimColor: true, children: " (current)" }),
6169
- hasDrift && /* @__PURE__ */ jsx6(Text5, { color: "magenta", children: " \u26A0" }),
6170
- /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
6171
- " ",
6172
- taskCount > 0 ? `[${taskCount}]` : ""
6173
- ] })
6174
- ] });
6175
- }
6176
- const task = row.task;
6177
- const taskLabel = task.title || task.task_slug;
6178
- const status = task.status || "";
6179
- const isPlaceholder = task.task_slug === "__none__";
6180
- const branch = getTreeBranch(isLastTask);
6181
- const activeAgent = getActiveAgent(task);
6182
- const progress = getChecklistProgress(task.checklist || []);
6183
- const relativeTime = task.updated_at ? formatRelativeTime(task.updated_at) : "";
6184
- if (isPlaceholder) {
6185
- return /* @__PURE__ */ jsxs4(Box5, { children: [
6186
- /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
6187
- " ",
6188
- branch,
6189
- " "
6190
- ] }),
6191
- /* @__PURE__ */ jsx6(Text5, { color: "dim", italic: true, children: taskLabel })
6192
- ] });
6193
- }
6194
- return /* @__PURE__ */ jsxs4(Box5, { children: [
6195
- /* @__PURE__ */ jsx6(Text5, { color: isSelected ? "cyan" : "dim", children: isSelected ? "\u25B8 " : " " }),
6196
- /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
6197
- branch,
6198
- " "
6199
- ] }),
6200
- /* @__PURE__ */ jsx6(Text5, { color: isSelected ? "cyan" : "white", children: "\u{1F4CB} " }),
6201
- /* @__PURE__ */ jsx6(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx6(Text5, { bold: isSelected, color: isSelected ? "cyan" : "white", children: taskLabel.length > 25 ? taskLabel.substring(0, 22) + "..." : taskLabel }) }),
6202
- activeAgent && /* @__PURE__ */ jsxs4(Text5, { children: [
6203
- /* @__PURE__ */ jsx6(Text5, { color: "dim", children: " " }),
6204
- /* @__PURE__ */ jsx6(Text5, { children: getPhaseIcon(activeAgent.agent) }),
6205
- /* @__PURE__ */ jsx6(Text5, { color: activeAgent.status === "in_progress" ? "yellow" : "green", children: getAgentStatusIcon(activeAgent.status) })
6206
- ] }),
6207
- progress.total > 0 && /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
6208
- " ",
6209
- getProgressBar(progress.percentage, 6),
6210
- " ",
6211
- progress.completed,
6212
- "/",
6213
- progress.total
6214
- ] }),
6215
- relativeTime && relativeTime !== "\u2014" && /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
6216
- " ",
6217
- relativeTime
6218
- ] }),
6219
- !activeAgent && status && /* @__PURE__ */ jsx6(Text5, { color: getStatusColor(status), children: ` ${getStatusIcon(status)} ${status}` })
6302
+ /* @__PURE__ */ jsx6(ProjectsFooter, {})
6220
6303
  ] });
6221
6304
  };
6222
6305
  }
@@ -6346,10 +6429,184 @@ var init_TaskDetails = __esm({
6346
6429
  }
6347
6430
  });
6348
6431
 
6432
+ // src/mcp/ui/components/TaskRow.tsx
6433
+ import "react";
6434
+ import { Box as Box7, Text as Text7 } from "ink";
6435
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
6436
+ function getActiveAgent(task) {
6437
+ if (!task.agents) return null;
6438
+ for (const [agent, info] of Object.entries(task.agents)) {
6439
+ if (info?.status === "in_progress") {
6440
+ return { agent, status: "in_progress" };
6441
+ }
6442
+ }
6443
+ const agentOrder = ["documentation", "executor", "planning", "research"];
6444
+ for (const agent of agentOrder) {
6445
+ if (task.agents[agent]?.status === "complete") {
6446
+ return { agent, status: "complete" };
6447
+ }
6448
+ }
6449
+ return null;
6450
+ }
6451
+ var TaskRow;
6452
+ var init_TaskRow = __esm({
6453
+ "src/mcp/ui/components/TaskRow.tsx"() {
6454
+ "use strict";
6455
+ init_ui_helpers();
6456
+ init_project_utils();
6457
+ TaskRow = ({
6458
+ row,
6459
+ isSelected,
6460
+ isExpanded,
6461
+ taskCount,
6462
+ hasDrift,
6463
+ isCurrentProject = false,
6464
+ isLastTask = false
6465
+ }) => {
6466
+ if (row.kind === "project") {
6467
+ const projectColor = isSelected ? "cyan" : isCurrentProject ? "yellow" : "white";
6468
+ const isBold = isSelected || isCurrentProject;
6469
+ return /* @__PURE__ */ jsxs6(Box7, { children: [
6470
+ /* @__PURE__ */ jsx8(Text7, { color: isSelected ? "cyan" : "dim", children: isSelected ? "\u25B8 " : " " }),
6471
+ /* @__PURE__ */ jsxs6(Text7, { bold: isBold, color: projectColor, children: [
6472
+ getFolderIcon(isExpanded),
6473
+ " ",
6474
+ formatProjectLabel(row.project)
6475
+ ] }),
6476
+ isCurrentProject && /* @__PURE__ */ jsx8(Text7, { color: "yellow", dimColor: true, children: " (current)" }),
6477
+ hasDrift && /* @__PURE__ */ jsx8(Text7, { color: "magenta", children: " \u26A0" }),
6478
+ /* @__PURE__ */ jsxs6(Text7, { color: "dim", children: [
6479
+ " ",
6480
+ taskCount > 0 ? `[${taskCount}]` : ""
6481
+ ] })
6482
+ ] });
6483
+ }
6484
+ const task = row.task;
6485
+ const taskLabel = task.title || task.task_slug;
6486
+ const status = task.status || "";
6487
+ const isPlaceholder = task.task_slug === "__none__";
6488
+ const branch = getTreeBranch(isLastTask);
6489
+ const activeAgent = getActiveAgent(task);
6490
+ const progress = getChecklistProgress(task.checklist || []);
6491
+ const relativeTime = task.updated_at ? formatRelativeTime(task.updated_at) : "";
6492
+ if (isPlaceholder) {
6493
+ return /* @__PURE__ */ jsxs6(Box7, { children: [
6494
+ /* @__PURE__ */ jsxs6(Text7, { color: "dim", children: [
6495
+ " ",
6496
+ branch,
6497
+ " "
6498
+ ] }),
6499
+ /* @__PURE__ */ jsx8(Text7, { color: "dim", italic: true, children: taskLabel })
6500
+ ] });
6501
+ }
6502
+ return /* @__PURE__ */ jsxs6(Box7, { children: [
6503
+ /* @__PURE__ */ jsx8(Text7, { color: isSelected ? "cyan" : "dim", children: isSelected ? "\u25B8 " : " " }),
6504
+ /* @__PURE__ */ jsxs6(Text7, { color: "dim", children: [
6505
+ branch,
6506
+ " "
6507
+ ] }),
6508
+ /* @__PURE__ */ jsx8(Text7, { color: isSelected ? "cyan" : "white", children: "\u{1F4CB} " }),
6509
+ /* @__PURE__ */ jsx8(Box7, { flexGrow: 1, children: /* @__PURE__ */ jsx8(Text7, { bold: isSelected, color: isSelected ? "cyan" : "white", children: taskLabel.length > 25 ? taskLabel.substring(0, 22) + "..." : taskLabel }) }),
6510
+ activeAgent && /* @__PURE__ */ jsxs6(Text7, { children: [
6511
+ /* @__PURE__ */ jsx8(Text7, { color: "dim", children: " " }),
6512
+ /* @__PURE__ */ jsx8(Text7, { children: getPhaseIcon(activeAgent.agent) }),
6513
+ /* @__PURE__ */ jsx8(Text7, { color: activeAgent.status === "in_progress" ? "yellow" : "green", children: getAgentStatusIcon(activeAgent.status) })
6514
+ ] }),
6515
+ progress.total > 0 && /* @__PURE__ */ jsxs6(Text7, { color: "dim", children: [
6516
+ " ",
6517
+ getProgressBar(progress.percentage, 6),
6518
+ " ",
6519
+ progress.completed,
6520
+ "/",
6521
+ progress.total
6522
+ ] }),
6523
+ relativeTime && relativeTime !== "\u2014" && /* @__PURE__ */ jsxs6(Text7, { color: "dim", children: [
6524
+ " ",
6525
+ relativeTime
6526
+ ] }),
6527
+ !activeAgent && status && /* @__PURE__ */ jsx8(Text7, { color: getStatusColor(status), children: ` ${getStatusIcon(status)} ${status}` })
6528
+ ] });
6529
+ };
6530
+ }
6531
+ });
6532
+
6533
+ // src/mcp/ui/components/TaskTree.tsx
6534
+ import "react";
6535
+ import { Box as Box8, Text as Text8 } from "ink";
6536
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
6537
+ var TaskTree;
6538
+ var init_TaskTree = __esm({
6539
+ "src/mcp/ui/components/TaskTree.tsx"() {
6540
+ "use strict";
6541
+ init_project_utils();
6542
+ init_TaskRow();
6543
+ TaskTree = ({
6544
+ flattenedRows,
6545
+ selectedIndex,
6546
+ expanded,
6547
+ taskCache,
6548
+ driftReports
6549
+ }) => {
6550
+ return /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", width: "50%", borderStyle: "single", borderColor: "dim", borderRight: true, paddingX: 1, children: flattenedRows.length === 0 ? /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: [
6551
+ /* @__PURE__ */ jsx9(Text8, { color: "dim", children: "No projects detected." }),
6552
+ /* @__PURE__ */ jsx9(Text8, { color: "dim", children: "Run the wizard to set up projects." })
6553
+ ] }) : /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: flattenedRows.map((row, idx) => {
6554
+ const k = projectKey(row.project);
6555
+ const isCurrentProject = row.kind === "project" ? row.isCurrentProject : false;
6556
+ const isLastTask = row.kind === "task" ? row.isLastTask : false;
6557
+ return /* @__PURE__ */ jsx9(
6558
+ TaskRow,
6559
+ {
6560
+ row,
6561
+ isSelected: idx === selectedIndex,
6562
+ isExpanded: expanded.has(k),
6563
+ taskCount: (taskCache[k] || []).length,
6564
+ hasDrift: !!driftReports[row.project.path]?.hasDrift,
6565
+ isCurrentProject,
6566
+ isLastTask
6567
+ },
6568
+ row.kind === "project" ? `p:${k}` : `t:${k}:${row.task.task_slug}`
6569
+ );
6570
+ }) }) });
6571
+ };
6572
+ }
6573
+ });
6574
+
6575
+ // src/mcp/ui/components/TaskViews.tsx
6576
+ import "react";
6577
+ import { Box as Box9, Text as Text9 } from "ink";
6578
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
6579
+ var TasksHeader, TasksFooter;
6580
+ var init_TaskViews = __esm({
6581
+ "src/mcp/ui/components/TaskViews.tsx"() {
6582
+ "use strict";
6583
+ TasksHeader = ({ projectCount, taskCount }) => /* @__PURE__ */ jsxs8(Box9, { paddingX: 1, justifyContent: "space-between", borderBottom: true, children: [
6584
+ /* @__PURE__ */ jsxs8(Box9, { children: [
6585
+ /* @__PURE__ */ jsx10(Text9, { bold: true, color: "cyan", children: "\u2699 Tasks" }),
6586
+ /* @__PURE__ */ jsx10(Text9, { color: "dim", children: " \u2502 " }),
6587
+ /* @__PURE__ */ jsxs8(Text9, { children: [
6588
+ projectCount,
6589
+ " projects"
6590
+ ] }),
6591
+ /* @__PURE__ */ jsx10(Text9, { color: "dim", children: " \u2022 " }),
6592
+ /* @__PURE__ */ jsxs8(Text9, { children: [
6593
+ taskCount,
6594
+ " tasks"
6595
+ ] })
6596
+ ] }),
6597
+ /* @__PURE__ */ jsx10(Text9, { color: "dim", children: "v0.3.14" })
6598
+ ] });
6599
+ TasksFooter = () => /* @__PURE__ */ jsxs8(Box9, { paddingX: 1, justifyContent: "space-between", borderTop: true, children: [
6600
+ /* @__PURE__ */ jsx10(Text9, { color: "dim", children: "\u2191\u2193:Nav Enter:Expand s:Cycle Status R:Refresh" }),
6601
+ /* @__PURE__ */ jsx10(Text9, { color: "dim", children: "Press 'q' to exit" })
6602
+ ] });
6603
+ }
6604
+ });
6605
+
6349
6606
  // src/mcp/ui/TasksView.tsx
6350
6607
  import { useEffect as useEffect4, useMemo as useMemo4, useState as useState4 } from "react";
6351
- import { Box as Box7, Text as Text7, useInput as useInput3 } from "ink";
6352
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
6608
+ import { Box as Box10, Text as Text10, useInput as useInput3 } from "ink";
6609
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
6353
6610
  function nextStatus(current) {
6354
6611
  const idx = STATUS_CYCLE.indexOf(current || "");
6355
6612
  if (idx === -1) return STATUS_CYCLE[0];
@@ -6362,8 +6619,9 @@ var init_TasksView = __esm({
6362
6619
  init_tasks_fs();
6363
6620
  init_ConfigContext();
6364
6621
  init_project_utils();
6365
- init_TaskRow();
6366
6622
  init_TaskDetails();
6623
+ init_TaskTree();
6624
+ init_TaskViews();
6367
6625
  STATUS_CYCLE = ["pending", "in_progress", "blocked", "complete"];
6368
6626
  TasksView = ({ projects: allProjects, workspacePath }) => {
6369
6627
  const { driftReports } = useConfig();
@@ -6484,55 +6742,26 @@ var init_TasksView = __esm({
6484
6742
  const selectedRow = flattenedRows[selectedIndex];
6485
6743
  const selectedTask = selectedRow?.kind === "task" && selectedRow.task.task_slug !== "__none__" ? selectedRow.task : null;
6486
6744
  const totalTasks = Object.values(taskCache).flat().length;
6487
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", borderStyle: "round", borderColor: "white", flexGrow: 1, children: [
6488
- /* @__PURE__ */ jsxs6(Box7, { paddingX: 1, justifyContent: "space-between", borderBottom: true, children: [
6489
- /* @__PURE__ */ jsxs6(Box7, { children: [
6490
- /* @__PURE__ */ jsx8(Text7, { bold: true, color: "cyan", children: "\u2699 Tasks" }),
6491
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: " \u2502 " }),
6492
- /* @__PURE__ */ jsxs6(Text7, { children: [
6493
- sortedProjects.length,
6494
- " projects"
6495
- ] }),
6496
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: " \u2022 " }),
6497
- /* @__PURE__ */ jsxs6(Text7, { children: [
6498
- totalTasks,
6499
- " tasks"
6500
- ] })
6501
- ] }),
6502
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: "v0.3.14" })
6503
- ] }),
6504
- errorLine && /* @__PURE__ */ jsx8(Box7, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsxs6(Text7, { color: "red", children: [
6745
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "white", flexGrow: 1, children: [
6746
+ /* @__PURE__ */ jsx11(TasksHeader, { projectCount: sortedProjects.length, taskCount: totalTasks }),
6747
+ errorLine && /* @__PURE__ */ jsx11(Box10, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsxs9(Text10, { color: "red", children: [
6505
6748
  "\u26A0 ",
6506
6749
  errorLine
6507
6750
  ] }) }),
6508
- /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", flexGrow: 1, children: [
6509
- /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", width: "50%", borderStyle: "single", borderColor: "dim", borderRight: true, paddingX: 1, children: flattenedRows.length === 0 ? /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", alignItems: "center", justifyContent: "center", flexGrow: 1, children: [
6510
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: "No projects detected." }),
6511
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: "Run the wizard to set up projects." })
6512
- ] }) : /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", marginTop: 1, children: flattenedRows.map((row, idx) => {
6513
- const k = projectKey(row.project);
6514
- const isCurrentProject = row.kind === "project" ? row.isCurrentProject : false;
6515
- const isLastTask = row.kind === "task" ? row.isLastTask : false;
6516
- return /* @__PURE__ */ jsx8(
6517
- TaskRow,
6518
- {
6519
- row,
6520
- isSelected: idx === selectedIndex,
6521
- isExpanded: expanded.has(k),
6522
- taskCount: (taskCache[k] || []).length,
6523
- hasDrift: !!driftReports[row.project.path]?.hasDrift,
6524
- isCurrentProject,
6525
- isLastTask
6526
- },
6527
- row.kind === "project" ? `p:${k}` : `t:${k}:${row.task.task_slug}`
6528
- );
6529
- }) }) }),
6530
- /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", width: "50%", paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx8(TaskDetails, { task: selectedTask }) })
6751
+ /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", flexGrow: 1, children: [
6752
+ /* @__PURE__ */ jsx11(
6753
+ TaskTree,
6754
+ {
6755
+ flattenedRows,
6756
+ selectedIndex,
6757
+ expanded,
6758
+ taskCache,
6759
+ driftReports
6760
+ }
6761
+ ),
6762
+ /* @__PURE__ */ jsx11(Box10, { flexDirection: "column", width: "50%", paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx11(TaskDetails, { task: selectedTask }) })
6531
6763
  ] }),
6532
- /* @__PURE__ */ jsxs6(Box7, { paddingX: 1, justifyContent: "space-between", borderTop: true, children: [
6533
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: "\u2191\u2193:Nav Enter:Expand s:Cycle Status R:Refresh" }),
6534
- /* @__PURE__ */ jsx8(Text7, { color: "dim", children: "Press 'q' to exit" })
6535
- ] })
6764
+ /* @__PURE__ */ jsx11(TasksFooter, {})
6536
6765
  ] });
6537
6766
  };
6538
6767
  }
@@ -6540,8 +6769,8 @@ var init_TasksView = __esm({
6540
6769
 
6541
6770
  // src/mcp/ui/LogViewer.tsx
6542
6771
  import "react";
6543
- import { Box as Box8, Text as Text8 } from "ink";
6544
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
6772
+ import { Box as Box11, Text as Text11 } from "ink";
6773
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
6545
6774
  var LogViewer;
6546
6775
  var init_LogViewer = __esm({
6547
6776
  "src/mcp/ui/LogViewer.tsx"() {
@@ -6551,16 +6780,16 @@ var init_LogViewer = __esm({
6551
6780
  const emptyLines = Math.max(0, height - visibleLogs.length);
6552
6781
  const padding = Array(emptyLines).fill("");
6553
6782
  const formatLog = (log) => {
6554
- if (log.includes("[RAG]")) return /* @__PURE__ */ jsx9(Text8, { color: "cyan", children: log });
6555
- if (log.includes("[ERROR]")) return /* @__PURE__ */ jsx9(Text8, { color: "red", children: log });
6556
- if (log.includes("[WARN]")) return /* @__PURE__ */ jsx9(Text8, { color: "yellow", children: log });
6557
- if (log.includes("[INFO]")) return /* @__PURE__ */ jsx9(Text8, { color: "green", children: log });
6558
- if (log.includes("Success")) return /* @__PURE__ */ jsx9(Text8, { color: "green", children: log });
6559
- return /* @__PURE__ */ jsx9(Text8, { children: log });
6783
+ if (log.includes("[RAG]")) return /* @__PURE__ */ jsx12(Text11, { color: "cyan", children: log });
6784
+ if (log.includes("[ERROR]")) return /* @__PURE__ */ jsx12(Text11, { color: "red", children: log });
6785
+ if (log.includes("[WARN]")) return /* @__PURE__ */ jsx12(Text11, { color: "yellow", children: log });
6786
+ if (log.includes("[INFO]")) return /* @__PURE__ */ jsx12(Text11, { color: "green", children: log });
6787
+ if (log.includes("Success")) return /* @__PURE__ */ jsx12(Text11, { color: "green", children: log });
6788
+ return /* @__PURE__ */ jsx12(Text11, { children: log });
6560
6789
  };
6561
- return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "white", paddingX: 1, height: height + 2, flexGrow: 1, children: [
6562
- padding.map((_, i) => /* @__PURE__ */ jsx9(Text8, { children: " " }, `empty-${i}`)),
6563
- visibleLogs.map((log, i) => /* @__PURE__ */ jsx9(Box8, { children: formatLog(log) }, `log-${i}`))
6790
+ return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "white", paddingX: 1, height: height + 2, flexGrow: 1, children: [
6791
+ padding.map((_, i) => /* @__PURE__ */ jsx12(Text11, { children: " " }, `empty-${i}`)),
6792
+ visibleLogs.map((log, i) => /* @__PURE__ */ jsx12(Box11, { children: formatLog(log) }, `log-${i}`))
6564
6793
  ] });
6565
6794
  };
6566
6795
  }
@@ -6568,28 +6797,28 @@ var init_LogViewer = __esm({
6568
6797
 
6569
6798
  // src/mcp/ui/StatusBoard.tsx
6570
6799
  import "react";
6571
- import { Box as Box9, Text as Text9 } from "ink";
6572
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
6800
+ import { Box as Box12, Text as Text12 } from "ink";
6801
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
6573
6802
  var StatusBoard;
6574
6803
  var init_StatusBoard = __esm({
6575
6804
  "src/mcp/ui/StatusBoard.tsx"() {
6576
6805
  "use strict";
6577
6806
  StatusBoard = ({ exposedLabel, port, pid, running, hasDrift }) => {
6578
- return /* @__PURE__ */ jsx10(Box9, { borderStyle: "single", borderColor: "white", paddingX: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs8(Text9, { children: [
6579
- running ? /* @__PURE__ */ jsx10(Text9, { color: "green", children: "\u25CF RUNNING" }) : /* @__PURE__ */ jsx10(Text9, { color: "red", children: "\u25CF STOPPED" }),
6807
+ return /* @__PURE__ */ jsx13(Box12, { borderStyle: "single", borderColor: "white", paddingX: 1, flexGrow: 1, children: /* @__PURE__ */ jsxs11(Text12, { children: [
6808
+ running ? /* @__PURE__ */ jsx13(Text12, { color: "green", children: "\u25CF RUNNING" }) : /* @__PURE__ */ jsx13(Text12, { color: "red", children: "\u25CF STOPPED" }),
6580
6809
  " ",
6581
6810
  "\u2502",
6582
6811
  " \u{1F4CB} ",
6583
- /* @__PURE__ */ jsx10(Text9, { color: "yellow", children: exposedLabel }),
6812
+ /* @__PURE__ */ jsx13(Text12, { color: "yellow", children: exposedLabel }),
6584
6813
  " ",
6585
6814
  "\u2502",
6586
6815
  " Port: ",
6587
- /* @__PURE__ */ jsx10(Text9, { color: "green", children: port }),
6816
+ /* @__PURE__ */ jsx13(Text12, { color: "green", children: port }),
6588
6817
  " ",
6589
6818
  "\u2502",
6590
6819
  " PID: ",
6591
- /* @__PURE__ */ jsx10(Text9, { color: "green", children: pid }),
6592
- hasDrift && /* @__PURE__ */ jsxs8(Text9, { color: "magenta", bold: true, children: [
6820
+ /* @__PURE__ */ jsx13(Text12, { color: "green", children: pid }),
6821
+ hasDrift && /* @__PURE__ */ jsxs11(Text12, { color: "magenta", bold: true, children: [
6593
6822
  " ",
6594
6823
  "\u2502",
6595
6824
  " \u2B06 UPDATE AVAILABLE"
@@ -6601,8 +6830,8 @@ var init_StatusBoard = __esm({
6601
6830
 
6602
6831
  // src/mcp/ui/components/TabBar.tsx
6603
6832
  import "react";
6604
- import { Box as Box10, Text as Text10, useInput as useInput4 } from "ink";
6605
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
6833
+ import { Box as Box13, Text as Text13, useInput as useInput4 } from "ink";
6834
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
6606
6835
  var TabBar;
6607
6836
  var init_TabBar = __esm({
6608
6837
  "src/mcp/ui/components/TabBar.tsx"() {
@@ -6632,11 +6861,11 @@ var init_TabBar = __esm({
6632
6861
  if (tab) onChange(tab.id);
6633
6862
  }
6634
6863
  });
6635
- return /* @__PURE__ */ jsxs9(Box10, { borderStyle: "single", paddingX: 1, borderColor: "gray", children: [
6864
+ return /* @__PURE__ */ jsxs12(Box13, { borderStyle: "single", paddingX: 1, borderColor: "gray", children: [
6636
6865
  tabs.map((tab, index) => {
6637
6866
  const isActive = tab.id === activeTab;
6638
- return /* @__PURE__ */ jsx11(Box10, { marginRight: 2, children: /* @__PURE__ */ jsx11(
6639
- Text10,
6867
+ return /* @__PURE__ */ jsx14(Box13, { marginRight: 2, children: /* @__PURE__ */ jsx14(
6868
+ Text13,
6640
6869
  {
6641
6870
  color: isActive ? "cyan" : "white",
6642
6871
  bold: isActive,
@@ -6645,8 +6874,8 @@ var init_TabBar = __esm({
6645
6874
  }
6646
6875
  ) }, tab.id);
6647
6876
  }),
6648
- /* @__PURE__ */ jsx11(Box10, { flexGrow: 1 }),
6649
- /* @__PURE__ */ jsx11(Text10, { color: "dim", children: "Use \u25C4/\u25BA arrows to navigate" })
6877
+ /* @__PURE__ */ jsx14(Box13, { flexGrow: 1 }),
6878
+ /* @__PURE__ */ jsx14(Text13, { color: "dim", children: "Use \u25C4/\u25BA arrows to navigate" })
6650
6879
  ] });
6651
6880
  };
6652
6881
  }
@@ -6658,9 +6887,9 @@ __export(App_exports, {
6658
6887
  App: () => App
6659
6888
  });
6660
6889
  import { useState as useState5, useEffect as useEffect6, useMemo as useMemo5, useCallback as useCallback3 } from "react";
6661
- import { Box as Box11, useInput as useInput5, useApp } from "ink";
6662
- import fs27 from "fs";
6663
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
6890
+ import { Box as Box14, useInput as useInput5, useApp } from "ink";
6891
+ import fs28 from "fs";
6892
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
6664
6893
  var App;
6665
6894
  var init_App = __esm({
6666
6895
  "src/mcp/ui/App.tsx"() {
@@ -6732,18 +6961,18 @@ var init_App = __esm({
6732
6961
  useEffect6(() => {
6733
6962
  const logPath = getLogFilePath();
6734
6963
  let lastSize = 0;
6735
- if (fs27.existsSync(logPath)) {
6736
- const stats = fs27.statSync(logPath);
6964
+ if (fs28.existsSync(logPath)) {
6965
+ const stats = fs28.statSync(logPath);
6737
6966
  lastSize = stats.size;
6738
6967
  }
6739
6968
  const interval = setInterval(() => {
6740
- if (fs27.existsSync(logPath)) {
6741
- const stats = fs27.statSync(logPath);
6969
+ if (fs28.existsSync(logPath)) {
6970
+ const stats = fs28.statSync(logPath);
6742
6971
  if (stats.size > lastSize) {
6743
6972
  const buffer = Buffer.alloc(stats.size - lastSize);
6744
- const fd = fs27.openSync(logPath, "r");
6745
- fs27.readSync(fd, buffer, 0, buffer.length, lastSize);
6746
- fs27.closeSync(fd);
6973
+ const fd = fs28.openSync(logPath, "r");
6974
+ fs28.readSync(fd, buffer, 0, buffer.length, lastSize);
6975
+ fs28.closeSync(fd);
6747
6976
  const newContent = buffer.toString("utf-8");
6748
6977
  const newLines = newContent.split("\n").filter((l) => l.trim());
6749
6978
  setLogs((prev) => {
@@ -6780,10 +7009,10 @@ var init_App = __esm({
6780
7009
  const handleConfigChange = useCallback3(() => {
6781
7010
  refreshData();
6782
7011
  }, [refreshData]);
6783
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", padding: 0, height: termHeight, children: [
6784
- /* @__PURE__ */ jsx12(TabBar, { tabs, activeTab, onChange: setActiveTab }),
6785
- /* @__PURE__ */ jsxs10(Box11, { marginTop: 1, flexGrow: 1, children: [
6786
- activeTab === "overview" && /* @__PURE__ */ jsx12(
7012
+ return /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", padding: 0, height: termHeight, children: [
7013
+ /* @__PURE__ */ jsx15(TabBar, { tabs, activeTab, onChange: setActiveTab }),
7014
+ /* @__PURE__ */ jsxs13(Box14, { marginTop: 1, flexGrow: 1, children: [
7015
+ activeTab === "overview" && /* @__PURE__ */ jsx15(
6787
7016
  Overview,
6788
7017
  {
6789
7018
  serverStatus: serverInfo,
@@ -6795,11 +7024,11 @@ var init_App = __esm({
6795
7024
  logs
6796
7025
  }
6797
7026
  ),
6798
- activeTab === "logs" && /* @__PURE__ */ jsx12(LogViewer, { logs, height: contentHeight }),
6799
- activeTab === "tasks" && /* @__PURE__ */ jsx12(TasksView, { projects, workspacePath }),
6800
- activeTab === "projects" && /* @__PURE__ */ jsx12(ProjectsView, { config, projects, onConfigChange: handleConfigChange, workspacePath })
7027
+ activeTab === "logs" && /* @__PURE__ */ jsx15(LogViewer, { logs, height: contentHeight }),
7028
+ activeTab === "tasks" && /* @__PURE__ */ jsx15(TasksView, { projects, workspacePath }),
7029
+ activeTab === "projects" && /* @__PURE__ */ jsx15(ProjectsView, { config, projects, onConfigChange: handleConfigChange, workspacePath })
6801
7030
  ] }),
6802
- /* @__PURE__ */ jsx12(Box11, { marginTop: 0, children: /* @__PURE__ */ jsx12(
7031
+ /* @__PURE__ */ jsx15(Box14, { marginTop: 0, children: /* @__PURE__ */ jsx15(
6803
7032
  StatusBoard,
6804
7033
  {
6805
7034
  exposedLabel: `${exposedProjects.length} / ${projects.length} projects`,
@@ -6817,7 +7046,7 @@ var init_App = __esm({
6817
7046
  // src/mcp/commands/start.ts
6818
7047
  import { confirm as confirm3, isCancel as isCancel5, text } from "@clack/prompts";
6819
7048
  async function handleStartServer() {
6820
- const React13 = await import("react");
7049
+ const React16 = await import("react");
6821
7050
  const { render } = await import("ink");
6822
7051
  const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
6823
7052
  const { ConfigProvider: ConfigProvider2 } = await Promise.resolve().then(() => (init_ConfigContext(), ConfigContext_exports));
@@ -6860,10 +7089,10 @@ async function handleStartServer() {
6860
7089
  }
6861
7090
  process.stdin.resume();
6862
7091
  const app = render(
6863
- React13.createElement(
7092
+ React16.createElement(
6864
7093
  ConfigProvider2,
6865
7094
  null,
6866
- React13.createElement(App2, {
7095
+ React16.createElement(App2, {
6867
7096
  initialPort,
6868
7097
  onExit: () => {
6869
7098
  }
@@ -6968,15 +7197,15 @@ __export(update_flow_exports, {
6968
7197
  });
6969
7198
  import { confirm as confirm5, spinner as spinner2, note as note6, outro as outro2, cancel as cancel2, isCancel as isCancel7 } from "@clack/prompts";
6970
7199
  import pc8 from "picocolors";
6971
- import * as fs28 from "fs";
6972
- import * as path29 from "path";
7200
+ import * as fs29 from "fs";
7201
+ import * as path30 from "path";
6973
7202
  import { stringify as stringify2, parse } from "yaml";
6974
7203
  function backupFile(filePath) {
6975
- if (!fs28.existsSync(filePath)) return null;
7204
+ if (!fs29.existsSync(filePath)) return null;
6976
7205
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T")[0] + "-" + Date.now();
6977
7206
  const backupPath = `${filePath}.${timestamp}.bak`;
6978
7207
  try {
6979
- fs28.copyFileSync(filePath, backupPath);
7208
+ fs29.copyFileSync(filePath, backupPath);
6980
7209
  return backupPath;
6981
7210
  } catch (e) {
6982
7211
  console.error(`Failed to backup ${filePath}:`, e);
@@ -6986,9 +7215,9 @@ function backupFile(filePath) {
6986
7215
  function getPackageVersion2() {
6987
7216
  try {
6988
7217
  const agentCoreDir = getAgentCoreDir();
6989
- const packageJsonPath = path29.join(path29.dirname(agentCoreDir), "package.json");
6990
- if (fs28.existsSync(packageJsonPath)) {
6991
- return JSON.parse(fs28.readFileSync(packageJsonPath, "utf8")).version;
7218
+ const packageJsonPath = path30.join(path30.dirname(agentCoreDir), "package.json");
7219
+ if (fs29.existsSync(packageJsonPath)) {
7220
+ return JSON.parse(fs29.readFileSync(packageJsonPath, "utf8")).version;
6992
7221
  }
6993
7222
  } catch (e) {
6994
7223
  }
@@ -7003,9 +7232,9 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
7003
7232
  const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
7004
7233
  const configFilePath = getConfigPath(workspacePath);
7005
7234
  let currentSyncedVersion;
7006
- if (fs28.existsSync(configFilePath)) {
7235
+ if (fs29.existsSync(configFilePath)) {
7007
7236
  try {
7008
- const content = fs28.readFileSync(configFilePath, "utf-8");
7237
+ const content = fs29.readFileSync(configFilePath, "utf-8");
7009
7238
  const config = parse(content);
7010
7239
  currentSyncedVersion = config.last_synced_version;
7011
7240
  } catch (e) {
@@ -7013,8 +7242,8 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
7013
7242
  }
7014
7243
  const driftReport = DriftService.checkDrift(dataPaths[0], currentSyncedVersion, runningVersion);
7015
7244
  const ideTargets = [];
7016
- if (fs28.existsSync(configFilePath)) {
7017
- const configContent = fs28.readFileSync(configFilePath, "utf-8");
7245
+ if (fs29.existsSync(configFilePath)) {
7246
+ const configContent = fs29.readFileSync(configFilePath, "utf-8");
7018
7247
  if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
7019
7248
  if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
7020
7249
  if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
@@ -7023,14 +7252,14 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
7023
7252
  const dirs = ["templates", "prompts", "docs"];
7024
7253
  const updatedFiles = [];
7025
7254
  for (const dir of dirs) {
7026
- const srcDir = path29.join(agentCoreDir, dir);
7027
- if (!fs28.existsSync(srcDir)) continue;
7255
+ const srcDir = path30.join(agentCoreDir, dir);
7256
+ if (!fs29.existsSync(srcDir)) continue;
7028
7257
  const syncFiles = (src, rel) => {
7029
- const entries = fs28.readdirSync(src, { withFileTypes: true });
7258
+ const entries = fs29.readdirSync(src, { withFileTypes: true });
7030
7259
  for (const entry of entries) {
7031
- const entrySrc = path29.join(src, entry.name);
7032
- const entryRel = path29.join(rel, entry.name);
7033
- const entryDest = path29.join(dataPath, entryRel);
7260
+ const entrySrc = path30.join(src, entry.name);
7261
+ const entryRel = path30.join(rel, entry.name);
7262
+ const entryDest = path30.join(dataPath, entryRel);
7034
7263
  if (entry.isDirectory()) {
7035
7264
  ensureDir(entryDest);
7036
7265
  syncFiles(entrySrc, entryRel);
@@ -7038,8 +7267,8 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
7038
7267
  if (driftReport.modifiedFiles.includes(entryRel)) {
7039
7268
  backupFile(entryDest);
7040
7269
  }
7041
- ensureDir(path29.dirname(entryDest));
7042
- fs28.copyFileSync(entrySrc, entryDest);
7270
+ ensureDir(path30.dirname(entryDest));
7271
+ fs29.copyFileSync(entrySrc, entryDest);
7043
7272
  updatedFiles.push(entryRel);
7044
7273
  }
7045
7274
  }
@@ -7050,12 +7279,12 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
7050
7279
  DriftService.saveManifest(dataPath, manifest);
7051
7280
  }
7052
7281
  const rrceHome = customGlobalPath || getDefaultRRCEHome2();
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");
7282
+ ensureDir(path30.join(rrceHome, "templates"));
7283
+ ensureDir(path30.join(rrceHome, "docs"));
7284
+ copyDirRecursive(path30.join(agentCoreDir, "templates"), path30.join(rrceHome, "templates"));
7285
+ copyDirRecursive(path30.join(agentCoreDir, "docs"), path30.join(rrceHome, "docs"));
7286
+ if (fs29.existsSync(configFilePath)) {
7287
+ const configContent = fs29.readFileSync(configFilePath, "utf-8");
7059
7288
  if (configContent.includes("copilot: true")) {
7060
7289
  const copilotPath = getAgentPromptPath(workspacePath, "copilot");
7061
7290
  ensureDir(copilotPath);
@@ -7077,21 +7306,21 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
7077
7306
  try {
7078
7307
  const yaml = parse(configContent);
7079
7308
  yaml.last_synced_version = runningVersion;
7080
- fs28.writeFileSync(configFilePath, stringify2(yaml));
7309
+ fs29.writeFileSync(configFilePath, stringify2(yaml));
7081
7310
  } catch (e) {
7082
7311
  console.error("Failed to update config.yaml version:", e);
7083
7312
  }
7084
7313
  }
7085
- const mcpPath = path29.join(rrceHome, "mcp.yaml");
7086
- if (fs28.existsSync(mcpPath)) {
7314
+ const mcpPath = path30.join(rrceHome, "mcp.yaml");
7315
+ if (fs29.existsSync(mcpPath)) {
7087
7316
  try {
7088
- const content = fs28.readFileSync(mcpPath, "utf-8");
7317
+ const content = fs29.readFileSync(mcpPath, "utf-8");
7089
7318
  const yaml = parse(content);
7090
7319
  if (yaml.projects) {
7091
7320
  const project = yaml.projects.find((p) => p.name === workspaceName);
7092
7321
  if (project) {
7093
7322
  project.last_synced_version = runningVersion;
7094
- fs28.writeFileSync(mcpPath, stringify2(yaml));
7323
+ fs29.writeFileSync(mcpPath, stringify2(yaml));
7095
7324
  }
7096
7325
  }
7097
7326
  } catch (e) {
@@ -7127,9 +7356,9 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
7127
7356
  const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
7128
7357
  const configFilePath = getConfigPath(workspacePath);
7129
7358
  let currentSyncedVersion;
7130
- if (fs28.existsSync(configFilePath)) {
7359
+ if (fs29.existsSync(configFilePath)) {
7131
7360
  try {
7132
- const content = fs28.readFileSync(configFilePath, "utf-8");
7361
+ const content = fs29.readFileSync(configFilePath, "utf-8");
7133
7362
  const config = parse(content);
7134
7363
  currentSyncedVersion = config.last_synced_version;
7135
7364
  } catch (e) {
@@ -7153,8 +7382,8 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
7153
7382
  ` \u2022 docs/ (documentation)`
7154
7383
  ];
7155
7384
  const ideTargets = [];
7156
- if (fs28.existsSync(configFilePath)) {
7157
- const configContent = fs28.readFileSync(configFilePath, "utf-8");
7385
+ if (fs29.existsSync(configFilePath)) {
7386
+ const configContent = fs29.readFileSync(configFilePath, "utf-8");
7158
7387
  if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
7159
7388
  if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
7160
7389
  if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
@@ -7183,14 +7412,14 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7183
7412
  const dirs = ["templates", "prompts", "docs"];
7184
7413
  const updatedFiles = [];
7185
7414
  for (const dir of dirs) {
7186
- const srcDir = path29.join(agentCoreDir, dir);
7187
- if (!fs28.existsSync(srcDir)) continue;
7415
+ const srcDir = path30.join(agentCoreDir, dir);
7416
+ if (!fs29.existsSync(srcDir)) continue;
7188
7417
  const syncFiles = (src, rel) => {
7189
- const entries = fs28.readdirSync(src, { withFileTypes: true });
7418
+ const entries = fs29.readdirSync(src, { withFileTypes: true });
7190
7419
  for (const entry of entries) {
7191
- const entrySrc = path29.join(src, entry.name);
7192
- const entryRel = path29.join(rel, entry.name);
7193
- const entryDest = path29.join(dataPath, entryRel);
7420
+ const entrySrc = path30.join(src, entry.name);
7421
+ const entryRel = path30.join(rel, entry.name);
7422
+ const entryDest = path30.join(dataPath, entryRel);
7194
7423
  if (entry.isDirectory()) {
7195
7424
  ensureDir(entryDest);
7196
7425
  syncFiles(entrySrc, entryRel);
@@ -7198,8 +7427,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7198
7427
  if (driftReport.modifiedFiles.includes(entryRel)) {
7199
7428
  backupFile(entryDest);
7200
7429
  }
7201
- ensureDir(path29.dirname(entryDest));
7202
- fs28.copyFileSync(entrySrc, entryDest);
7430
+ ensureDir(path30.dirname(entryDest));
7431
+ fs29.copyFileSync(entrySrc, entryDest);
7203
7432
  updatedFiles.push(entryRel);
7204
7433
  }
7205
7434
  }
@@ -7210,12 +7439,12 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7210
7439
  DriftService.saveManifest(dataPath, manifest);
7211
7440
  }
7212
7441
  const rrceHome = customGlobalPath || getDefaultRRCEHome2();
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");
7442
+ ensureDir(path30.join(rrceHome, "templates"));
7443
+ ensureDir(path30.join(rrceHome, "docs"));
7444
+ copyDirRecursive(path30.join(agentCoreDir, "templates"), path30.join(rrceHome, "templates"));
7445
+ copyDirRecursive(path30.join(agentCoreDir, "docs"), path30.join(rrceHome, "docs"));
7446
+ if (fs29.existsSync(configFilePath)) {
7447
+ const configContent = fs29.readFileSync(configFilePath, "utf-8");
7219
7448
  if (configContent.includes("copilot: true")) {
7220
7449
  const copilotPath = getAgentPromptPath(workspacePath, "copilot");
7221
7450
  ensureDir(copilotPath);
@@ -7237,21 +7466,21 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7237
7466
  try {
7238
7467
  const yaml = parse(configContent);
7239
7468
  yaml.last_synced_version = runningVersion;
7240
- fs28.writeFileSync(configFilePath, stringify2(yaml));
7469
+ fs29.writeFileSync(configFilePath, stringify2(yaml));
7241
7470
  } catch (e) {
7242
7471
  console.error("Failed to update config.yaml version:", e);
7243
7472
  }
7244
7473
  }
7245
- const mcpPath = path29.join(rrceHome, "mcp.yaml");
7246
- if (fs28.existsSync(mcpPath)) {
7474
+ const mcpPath = path30.join(rrceHome, "mcp.yaml");
7475
+ if (fs29.existsSync(mcpPath)) {
7247
7476
  try {
7248
- const content = fs28.readFileSync(mcpPath, "utf-8");
7477
+ const content = fs29.readFileSync(mcpPath, "utf-8");
7249
7478
  const yaml = parse(content);
7250
7479
  if (yaml.projects) {
7251
7480
  const project = yaml.projects.find((p) => p.name === workspaceName);
7252
7481
  if (project) {
7253
7482
  project.last_synced_version = runningVersion;
7254
- fs28.writeFileSync(mcpPath, stringify2(yaml));
7483
+ fs29.writeFileSync(mcpPath, stringify2(yaml));
7255
7484
  }
7256
7485
  }
7257
7486
  } catch (e) {
@@ -7286,8 +7515,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
7286
7515
  }
7287
7516
  }
7288
7517
  function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
7289
- const globalPath = path29.join(customGlobalPath, "workspaces", workspaceName);
7290
- const workspacePath = path29.join(workspaceRoot, ".rrce-workflow");
7518
+ const globalPath = path30.join(customGlobalPath, "workspaces", workspaceName);
7519
+ const workspacePath = path30.join(workspaceRoot, ".rrce-workflow");
7291
7520
  switch (mode) {
7292
7521
  case "global":
7293
7522
  return [globalPath];
@@ -7310,8 +7539,8 @@ var init_update_flow = __esm({
7310
7539
  // src/commands/wizard/index.ts
7311
7540
  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";
7312
7541
  import pc13 from "picocolors";
7313
- import * as fs32 from "fs";
7314
- import * as path31 from "path";
7542
+ import * as fs33 from "fs";
7543
+ import * as path32 from "path";
7315
7544
  import { parse as parse2 } from "yaml";
7316
7545
 
7317
7546
  // src/lib/git.ts
@@ -7453,22 +7682,22 @@ async function promptConfirmation() {
7453
7682
  init_paths();
7454
7683
  init_prompts();
7455
7684
  init_utils();
7456
- import * as fs10 from "fs";
7457
- import * as path12 from "path";
7685
+ import * as fs11 from "fs";
7686
+ import * as path13 from "path";
7458
7687
  import pc4 from "picocolors";
7459
7688
  import { note as note2 } from "@clack/prompts";
7460
7689
 
7461
7690
  // src/commands/wizard/vscode.ts
7462
7691
  init_paths();
7463
7692
  init_detection();
7464
- import * as fs8 from "fs";
7465
- import * as path9 from "path";
7693
+ import * as fs9 from "fs";
7694
+ import * as path10 from "path";
7466
7695
  function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
7467
- const workspaceFilePath = path9.join(workspacePath, `${workspaceName}.code-workspace`);
7696
+ const workspaceFilePath = path10.join(workspacePath, `${workspaceName}.code-workspace`);
7468
7697
  let workspace;
7469
- if (fs8.existsSync(workspaceFilePath)) {
7698
+ if (fs9.existsSync(workspaceFilePath)) {
7470
7699
  try {
7471
- const content = fs8.readFileSync(workspaceFilePath, "utf-8");
7700
+ const content = fs9.readFileSync(workspaceFilePath, "utf-8");
7472
7701
  workspace = JSON.parse(content);
7473
7702
  } catch {
7474
7703
  workspace = { folders: [], settings: {} };
@@ -7501,7 +7730,7 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
7501
7730
  for (const project of projects) {
7502
7731
  const sourceLabel = project.source === "global" ? "global" : "local";
7503
7732
  const folderPath = project.dataPath;
7504
- if (fs8.existsSync(folderPath)) {
7733
+ if (fs9.existsSync(folderPath)) {
7505
7734
  referenceFolderPaths.push(folderPath);
7506
7735
  workspace.folders.push({
7507
7736
  path: folderPath,
@@ -7513,8 +7742,8 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
7513
7742
  const projectNames = linkedProjects;
7514
7743
  const rrceHome = customGlobalPath || getRRCEHome();
7515
7744
  for (const projectName of projectNames) {
7516
- const folderPath = path9.join(rrceHome, "workspaces", projectName);
7517
- if (fs8.existsSync(folderPath)) {
7745
+ const folderPath = path10.join(rrceHome, "workspaces", projectName);
7746
+ if (fs9.existsSync(folderPath)) {
7518
7747
  referenceFolderPaths.push(folderPath);
7519
7748
  workspace.folders.push({
7520
7749
  path: folderPath,
@@ -7540,23 +7769,23 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
7540
7769
  ...readonlyPatterns
7541
7770
  };
7542
7771
  }
7543
- fs8.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
7772
+ fs9.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
7544
7773
  }
7545
7774
 
7546
7775
  // src/commands/wizard/setup-actions.ts
7547
7776
  init_install();
7548
7777
  function detectExistingProject(workspacePath, workspaceName, globalPath) {
7549
7778
  const rrceHome = globalPath || getDefaultRRCEHome2();
7550
- const globalConfigPath = path12.join(rrceHome, "workspaces", workspaceName, "config.yaml");
7551
- const workspaceConfigPath = path12.join(workspacePath, ".rrce-workflow", "config.yaml");
7779
+ const globalConfigPath = path13.join(rrceHome, "workspaces", workspaceName, "config.yaml");
7780
+ const workspaceConfigPath = path13.join(workspacePath, ".rrce-workflow", "config.yaml");
7552
7781
  const hasOpenCodeAgents = checkForRRCEAgents();
7553
- if (fs10.existsSync(globalConfigPath)) {
7782
+ if (fs11.existsSync(globalConfigPath)) {
7554
7783
  return {
7555
7784
  isExisting: true,
7556
7785
  currentMode: "global",
7557
7786
  configPath: globalConfigPath
7558
7787
  };
7559
- } else if (fs10.existsSync(workspaceConfigPath)) {
7788
+ } else if (fs11.existsSync(workspaceConfigPath)) {
7560
7789
  return {
7561
7790
  isExisting: true,
7562
7791
  currentMode: "workspace",
@@ -7576,9 +7805,9 @@ function detectExistingProject(workspacePath, workspaceName, globalPath) {
7576
7805
  };
7577
7806
  }
7578
7807
  function checkForRRCEAgents() {
7579
- if (!fs10.existsSync(OPENCODE_CONFIG)) return false;
7808
+ if (!fs11.existsSync(OPENCODE_CONFIG)) return false;
7580
7809
  try {
7581
- const config = JSON.parse(fs10.readFileSync(OPENCODE_CONFIG, "utf8"));
7810
+ const config = JSON.parse(fs11.readFileSync(OPENCODE_CONFIG, "utf8"));
7582
7811
  const agentKeys = Object.keys(config.agent || config.agents || {});
7583
7812
  return agentKeys.some((key) => key.startsWith("rrce_"));
7584
7813
  } catch {
@@ -7588,23 +7817,23 @@ function checkForRRCEAgents() {
7588
7817
  function createDirectoryStructure(dataPaths) {
7589
7818
  for (const dataPath of dataPaths) {
7590
7819
  ensureDir(dataPath);
7591
- ensureDir(path12.join(dataPath, "knowledge"));
7592
- ensureDir(path12.join(dataPath, "refs"));
7593
- ensureDir(path12.join(dataPath, "tasks"));
7594
- ensureDir(path12.join(dataPath, "templates"));
7820
+ ensureDir(path13.join(dataPath, "knowledge"));
7821
+ ensureDir(path13.join(dataPath, "refs"));
7822
+ ensureDir(path13.join(dataPath, "tasks"));
7823
+ ensureDir(path13.join(dataPath, "templates"));
7595
7824
  }
7596
7825
  }
7597
7826
  async function installAgentPrompts(config, workspacePath, dataPaths) {
7598
7827
  const agentCoreDir = getAgentCoreDir();
7599
7828
  syncMetadataToAll(agentCoreDir, dataPaths);
7600
- copyDirToAllStoragePaths(path12.join(agentCoreDir, "templates"), "templates", dataPaths);
7601
- copyDirToAllStoragePaths(path12.join(agentCoreDir, "prompts"), "prompts", dataPaths);
7602
- copyDirToAllStoragePaths(path12.join(agentCoreDir, "docs"), "docs", dataPaths);
7829
+ copyDirToAllStoragePaths(path13.join(agentCoreDir, "templates"), "templates", dataPaths);
7830
+ copyDirToAllStoragePaths(path13.join(agentCoreDir, "prompts"), "prompts", dataPaths);
7831
+ copyDirToAllStoragePaths(path13.join(agentCoreDir, "docs"), "docs", dataPaths);
7603
7832
  const rrceHome = config.globalPath || getDefaultRRCEHome2();
7604
- ensureDir(path12.join(rrceHome, "templates"));
7605
- ensureDir(path12.join(rrceHome, "docs"));
7606
- copyDirRecursive(path12.join(agentCoreDir, "templates"), path12.join(rrceHome, "templates"));
7607
- copyDirRecursive(path12.join(agentCoreDir, "docs"), path12.join(rrceHome, "docs"));
7833
+ ensureDir(path13.join(rrceHome, "templates"));
7834
+ ensureDir(path13.join(rrceHome, "docs"));
7835
+ copyDirRecursive(path13.join(agentCoreDir, "templates"), path13.join(rrceHome, "templates"));
7836
+ copyDirRecursive(path13.join(agentCoreDir, "docs"), path13.join(rrceHome, "docs"));
7608
7837
  const needsIDEPrompts = config.storageMode === "workspace" && (config.tools.includes("copilot") || config.tools.includes("antigravity")) || config.tools.includes("opencode");
7609
7838
  if (needsIDEPrompts) {
7610
7839
  const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
@@ -7633,11 +7862,11 @@ function createWorkspaceConfig(config, workspacePath, workspaceName) {
7633
7862
  let configPath;
7634
7863
  if (config.storageMode === "global") {
7635
7864
  const rrceHome = config.globalPath || getDefaultRRCEHome2();
7636
- configPath = path12.join(rrceHome, "workspaces", workspaceName, "config.yaml");
7865
+ configPath = path13.join(rrceHome, "workspaces", workspaceName, "config.yaml");
7637
7866
  } else {
7638
- configPath = path12.join(workspacePath, ".rrce-workflow", "config.yaml");
7867
+ configPath = path13.join(workspacePath, ".rrce-workflow", "config.yaml");
7639
7868
  }
7640
- ensureDir(path12.dirname(configPath));
7869
+ ensureDir(path13.dirname(configPath));
7641
7870
  let content = `# RRCE-Workflow Configuration
7642
7871
  version: 1
7643
7872
 
@@ -7673,7 +7902,7 @@ linked_projects:
7673
7902
  `;
7674
7903
  });
7675
7904
  }
7676
- fs10.writeFileSync(configPath, content);
7905
+ fs11.writeFileSync(configPath, content);
7677
7906
  }
7678
7907
  async function registerWithMCP(config, workspacePath, workspaceName) {
7679
7908
  if (!config.exposeToMCP) return;
@@ -7700,8 +7929,8 @@ You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
7700
7929
  }
7701
7930
  }
7702
7931
  function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
7703
- const globalPath = path12.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
7704
- const workspacePath = path12.join(workspaceRoot, ".rrce-workflow");
7932
+ const globalPath = path13.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
7933
+ const workspacePath = path13.join(workspaceRoot, ".rrce-workflow");
7705
7934
  switch (mode) {
7706
7935
  case "global":
7707
7936
  return [globalPath];
@@ -7988,7 +8217,7 @@ async function handlePostSetup(config, workspacePath, workspaceName, linkedProje
7988
8217
  init_paths();
7989
8218
  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";
7990
8219
  import pc10 from "picocolors";
7991
- import * as fs29 from "fs";
8220
+ import * as fs30 from "fs";
7992
8221
  init_detection();
7993
8222
  async function runLinkProjectsFlow(workspacePath, workspaceName) {
7994
8223
  const projects = scanForProjects({
@@ -8027,7 +8256,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
8027
8256
  const s = spinner4();
8028
8257
  s.start("Linking projects");
8029
8258
  const configFilePath = getConfigPath(workspacePath);
8030
- let configContent = fs29.readFileSync(configFilePath, "utf-8");
8259
+ let configContent = fs30.readFileSync(configFilePath, "utf-8");
8031
8260
  if (configContent.includes("linked_projects:")) {
8032
8261
  const lines = configContent.split("\n");
8033
8262
  const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
@@ -8054,7 +8283,7 @@ linked_projects:
8054
8283
  `;
8055
8284
  });
8056
8285
  }
8057
- fs29.writeFileSync(configFilePath, configContent);
8286
+ fs30.writeFileSync(configFilePath, configContent);
8058
8287
  generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
8059
8288
  s.stop("Projects linked");
8060
8289
  const workspaceFile = `${workspaceName}.code-workspace`;
@@ -8090,15 +8319,15 @@ init_paths();
8090
8319
  init_utils();
8091
8320
  import { confirm as confirm8, spinner as spinner5, note as note9, outro as outro5, cancel as cancel5, isCancel as isCancel10 } from "@clack/prompts";
8092
8321
  import pc11 from "picocolors";
8093
- import * as fs30 from "fs";
8094
- import * as path30 from "path";
8322
+ import * as fs31 from "fs";
8323
+ import * as path31 from "path";
8095
8324
  async function runSyncToGlobalFlow(workspacePath, workspaceName) {
8096
8325
  const localPath = getLocalWorkspacePath(workspacePath);
8097
8326
  const customGlobalPath = getEffectiveRRCEHome(workspacePath);
8098
- const globalPath = path30.join(customGlobalPath, "workspaces", workspaceName);
8327
+ const globalPath = path31.join(customGlobalPath, "workspaces", workspaceName);
8099
8328
  const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
8100
8329
  const existingDirs = subdirs.filter(
8101
- (dir) => fs30.existsSync(path30.join(localPath, dir))
8330
+ (dir) => fs31.existsSync(path31.join(localPath, dir))
8102
8331
  );
8103
8332
  if (existingDirs.length === 0) {
8104
8333
  outro5(pc11.yellow("No data found in workspace storage to sync."));
@@ -8124,8 +8353,8 @@ Destination: ${pc11.cyan(globalPath)}`,
8124
8353
  try {
8125
8354
  ensureDir(globalPath);
8126
8355
  for (const dir of existingDirs) {
8127
- const srcDir = path30.join(localPath, dir);
8128
- const destDir = path30.join(globalPath, dir);
8356
+ const srcDir = path31.join(localPath, dir);
8357
+ const destDir = path31.join(globalPath, dir);
8129
8358
  ensureDir(destDir);
8130
8359
  copyDirRecursive(srcDir, destDir);
8131
8360
  }
@@ -8153,7 +8382,7 @@ init_update_flow();
8153
8382
  // src/commands/wizard/delete-flow.ts
8154
8383
  import { multiselect as multiselect5, confirm as confirm9, spinner as spinner6, note as note10, cancel as cancel6, isCancel as isCancel11 } from "@clack/prompts";
8155
8384
  import pc12 from "picocolors";
8156
- import * as fs31 from "fs";
8385
+ import * as fs32 from "fs";
8157
8386
  init_detection();
8158
8387
  init_config();
8159
8388
  async function runDeleteGlobalProjectFlow(availableProjects) {
@@ -8197,8 +8426,8 @@ Are you sure?`,
8197
8426
  for (const projectName of projectsToDelete) {
8198
8427
  const project = globalProjects.find((p) => p.name === projectName);
8199
8428
  if (!project) continue;
8200
- if (fs31.existsSync(project.dataPath)) {
8201
- fs31.rmSync(project.dataPath, { recursive: true, force: true });
8429
+ if (fs32.existsSync(project.dataPath)) {
8430
+ fs32.rmSync(project.dataPath, { recursive: true, force: true });
8202
8431
  }
8203
8432
  const newConfig = removeProjectConfig(mcpConfig, projectName);
8204
8433
  configChanged = true;
@@ -8220,9 +8449,9 @@ init_config();
8220
8449
  function getPackageVersion3() {
8221
8450
  try {
8222
8451
  const agentCoreDir = getAgentCoreDir();
8223
- const packageJsonPath = path31.join(path31.dirname(agentCoreDir), "package.json");
8224
- if (fs32.existsSync(packageJsonPath)) {
8225
- return JSON.parse(fs32.readFileSync(packageJsonPath, "utf8")).version;
8452
+ const packageJsonPath = path32.join(path32.dirname(agentCoreDir), "package.json");
8453
+ if (fs33.existsSync(packageJsonPath)) {
8454
+ return JSON.parse(fs33.readFileSync(packageJsonPath, "utf8")).version;
8226
8455
  }
8227
8456
  } catch (e) {
8228
8457
  }
@@ -8230,9 +8459,9 @@ function getPackageVersion3() {
8230
8459
  }
8231
8460
  function getLastSyncedVersion(workspacePath, workspaceName) {
8232
8461
  const configFilePath = getConfigPath(workspacePath);
8233
- if (fs32.existsSync(configFilePath)) {
8462
+ if (fs33.existsSync(configFilePath)) {
8234
8463
  try {
8235
- const content = fs32.readFileSync(configFilePath, "utf-8");
8464
+ const content = fs33.readFileSync(configFilePath, "utf-8");
8236
8465
  const config = parse2(content);
8237
8466
  if (config.last_synced_version) {
8238
8467
  return config.last_synced_version;
@@ -8241,10 +8470,10 @@ function getLastSyncedVersion(workspacePath, workspaceName) {
8241
8470
  }
8242
8471
  }
8243
8472
  const rrceHome = getEffectiveRRCEHome(workspacePath) || getDefaultRRCEHome2();
8244
- const mcpPath = path31.join(rrceHome, "mcp.yaml");
8245
- if (fs32.existsSync(mcpPath)) {
8473
+ const mcpPath = path32.join(rrceHome, "mcp.yaml");
8474
+ if (fs33.existsSync(mcpPath)) {
8246
8475
  try {
8247
- const content = fs32.readFileSync(mcpPath, "utf-8");
8476
+ const content = fs33.readFileSync(mcpPath, "utf-8");
8248
8477
  const config = parse2(content);
8249
8478
  const project = config.projects?.find((p) => p.name === workspaceName);
8250
8479
  if (project?.last_synced_version) {
@@ -8314,11 +8543,11 @@ Workspace: ${pc13.bold(workspaceName)}`,
8314
8543
  workspacePath
8315
8544
  });
8316
8545
  const configFilePath = getConfigPath(workspacePath);
8317
- let isAlreadyConfigured = fs32.existsSync(configFilePath);
8546
+ let isAlreadyConfigured = fs33.existsSync(configFilePath);
8318
8547
  let currentStorageMode = null;
8319
8548
  if (isAlreadyConfigured) {
8320
8549
  try {
8321
- const configContent = fs32.readFileSync(configFilePath, "utf-8");
8550
+ const configContent = fs33.readFileSync(configFilePath, "utf-8");
8322
8551
  const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
8323
8552
  currentStorageMode = modeMatch?.[1] ?? null;
8324
8553
  } catch {
@@ -8335,7 +8564,7 @@ Workspace: ${pc13.bold(workspaceName)}`,
8335
8564
  }
8336
8565
  }
8337
8566
  const localDataPath = getLocalWorkspacePath(workspacePath);
8338
- const hasLocalData = fs32.existsSync(localDataPath);
8567
+ const hasLocalData = fs33.existsSync(localDataPath);
8339
8568
  if (isAlreadyConfigured) {
8340
8569
  const continueToMenu = await checkAndPromptUpdate(workspacePath, workspaceName, currentStorageMode);
8341
8570
  if (!continueToMenu) {