rrce-workflow 0.3.22 → 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/agent-core/prompts/_base.md +18 -24
- package/agent-core/prompts/design.md +19 -47
- package/agent-core/prompts/develop.md +10 -22
- package/agent-core/prompts/doctor.md +1 -1
- package/agent-core/prompts/documentation.md +1 -0
- package/agent-core/prompts/init.md +26 -25
- package/agent-core/prompts/orchestrator.md +36 -4
- package/dist/index.js +1353 -1152
- package/package.json +1 -1
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
|
|
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
|
|
1082
|
+
return path9.join(os2.homedir(), ".config", "opencode", "command");
|
|
1042
1083
|
}
|
|
1043
|
-
return
|
|
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 =
|
|
1058
|
-
if (
|
|
1059
|
-
return
|
|
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 (
|
|
1077
|
-
const entries =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 (!
|
|
1144
|
+
if (!fs8.existsSync(opencodePath)) {
|
|
1140
1145
|
return;
|
|
1141
1146
|
}
|
|
1142
1147
|
try {
|
|
1143
|
-
const config = JSON.parse(
|
|
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
|
-
|
|
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 =
|
|
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
|
|
1213
|
-
const promptsDir =
|
|
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 =
|
|
1200
|
+
const baseName = path9.basename(prompt.filePath, ".md");
|
|
1219
1201
|
const agentId = `rrce_${baseName}`;
|
|
1220
1202
|
const promptFileName = `rrce-${baseName}.md`;
|
|
1221
|
-
const promptFilePath =
|
|
1203
|
+
const promptFilePath = path9.join(promptsDir, promptFileName);
|
|
1222
1204
|
const fullContent = baseProtocol ? `${baseProtocol}
|
|
1223
1205
|
${prompt.content}` : prompt.content;
|
|
1224
|
-
|
|
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,22 +1211,22 @@ ${prompt.content}` : prompt.content;
|
|
|
1229
1211
|
newAgents[agentId] = agentConfig;
|
|
1230
1212
|
}
|
|
1231
1213
|
updateOpenCodeConfig(newAgents);
|
|
1232
|
-
if (
|
|
1233
|
-
const config = JSON.parse(
|
|
1214
|
+
if (fs8.existsSync(openCodeConfigPath)) {
|
|
1215
|
+
const config = JSON.parse(fs8.readFileSync(openCodeConfigPath, "utf8"));
|
|
1234
1216
|
if (!config.agent) config.agent = {};
|
|
1235
|
-
|
|
1217
|
+
fs8.writeFileSync(openCodeConfigPath, JSON.stringify(config, null, 2));
|
|
1236
1218
|
}
|
|
1237
1219
|
} catch (e) {
|
|
1238
1220
|
console.error("Failed to update global OpenCode config with agents:", e);
|
|
1239
1221
|
throw e;
|
|
1240
1222
|
}
|
|
1241
1223
|
} else {
|
|
1242
|
-
const opencodeBaseDir =
|
|
1224
|
+
const opencodeBaseDir = path9.join(dataPath, ".opencode", "agent");
|
|
1243
1225
|
ensureDir(opencodeBaseDir);
|
|
1244
1226
|
clearDirectory(opencodeBaseDir);
|
|
1245
1227
|
const baseProtocol = loadBaseProtocol();
|
|
1246
1228
|
for (const prompt of agentPrompts) {
|
|
1247
|
-
const baseName =
|
|
1229
|
+
const baseName = path9.basename(prompt.filePath, ".md");
|
|
1248
1230
|
const agentId = `rrce_${baseName}`;
|
|
1249
1231
|
const agentConfig = convertToOpenCodeAgent(prompt);
|
|
1250
1232
|
if (baseName === "develop") {
|
|
@@ -1259,16 +1241,53 @@ ${stringify({
|
|
|
1259
1241
|
tools: agentConfig.tools
|
|
1260
1242
|
})}---
|
|
1261
1243
|
${fullContent}`;
|
|
1262
|
-
|
|
1244
|
+
fs8.writeFileSync(path9.join(opencodeBaseDir, `${agentId}.md`), content);
|
|
1263
1245
|
}
|
|
1264
1246
|
}
|
|
1265
1247
|
generateOpenCodeCommands(prompts, mode, dataPath);
|
|
1266
1248
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
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"() {
|
|
1269
1278
|
"use strict";
|
|
1270
1279
|
init_paths();
|
|
1271
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();
|
|
1272
1291
|
}
|
|
1273
1292
|
});
|
|
1274
1293
|
|
|
@@ -1301,14 +1320,14 @@ var init_types = __esm({
|
|
|
1301
1320
|
});
|
|
1302
1321
|
|
|
1303
1322
|
// src/mcp/config-utils.ts
|
|
1304
|
-
import * as
|
|
1323
|
+
import * as path11 from "path";
|
|
1305
1324
|
function normalizeProjectPath(projectPath) {
|
|
1306
1325
|
let normalized = projectPath;
|
|
1307
1326
|
while (normalized.length > 1 && (normalized.endsWith("/") || normalized.endsWith("\\"))) {
|
|
1308
1327
|
normalized = normalized.slice(0, -1);
|
|
1309
1328
|
}
|
|
1310
1329
|
if (normalized.endsWith(".rrce-workflow")) {
|
|
1311
|
-
return
|
|
1330
|
+
return path11.dirname(normalized);
|
|
1312
1331
|
}
|
|
1313
1332
|
return normalized;
|
|
1314
1333
|
}
|
|
@@ -1347,8 +1366,8 @@ __export(config_exports, {
|
|
|
1347
1366
|
saveMCPConfig: () => saveMCPConfig,
|
|
1348
1367
|
setProjectConfig: () => setProjectConfig
|
|
1349
1368
|
});
|
|
1350
|
-
import * as
|
|
1351
|
-
import * as
|
|
1369
|
+
import * as fs10 from "fs";
|
|
1370
|
+
import * as path12 from "path";
|
|
1352
1371
|
import YAML from "yaml";
|
|
1353
1372
|
function migrateConfig(config) {
|
|
1354
1373
|
let changed = false;
|
|
@@ -1367,15 +1386,15 @@ function migrateConfig(config) {
|
|
|
1367
1386
|
function getMCPConfigPath() {
|
|
1368
1387
|
const workspaceRoot = detectWorkspaceRoot();
|
|
1369
1388
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1370
|
-
return
|
|
1389
|
+
return path12.join(rrceHome, "mcp.yaml");
|
|
1371
1390
|
}
|
|
1372
1391
|
function loadMCPConfig() {
|
|
1373
1392
|
const configPath = getMCPConfigPath();
|
|
1374
|
-
if (!
|
|
1393
|
+
if (!fs10.existsSync(configPath)) {
|
|
1375
1394
|
return { ...DEFAULT_MCP_CONFIG };
|
|
1376
1395
|
}
|
|
1377
1396
|
try {
|
|
1378
|
-
const content =
|
|
1397
|
+
const content = fs10.readFileSync(configPath, "utf-8");
|
|
1379
1398
|
let config = parseMCPConfig(content);
|
|
1380
1399
|
config = migrateConfig(config);
|
|
1381
1400
|
return config;
|
|
@@ -1387,9 +1406,9 @@ function ensureMCPGlobalPath() {
|
|
|
1387
1406
|
const workspaceRoot = detectWorkspaceRoot();
|
|
1388
1407
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1389
1408
|
if (rrceHome.startsWith(".") || rrceHome.includes(".rrce-workflow/")) {
|
|
1390
|
-
const configPath =
|
|
1391
|
-
if (
|
|
1392
|
-
const content =
|
|
1409
|
+
const configPath = path12.join(workspaceRoot, ".rrce-workflow", "config.yaml");
|
|
1410
|
+
if (fs10.existsSync(configPath)) {
|
|
1411
|
+
const content = fs10.readFileSync(configPath, "utf-8");
|
|
1393
1412
|
const modeMatch = content.match(/mode:\s*(global|workspace)/);
|
|
1394
1413
|
if (modeMatch?.[1] === "workspace") {
|
|
1395
1414
|
return {
|
|
@@ -1407,12 +1426,12 @@ function ensureMCPGlobalPath() {
|
|
|
1407
1426
|
}
|
|
1408
1427
|
function saveMCPConfig(config) {
|
|
1409
1428
|
const configPath = getMCPConfigPath();
|
|
1410
|
-
const dir =
|
|
1411
|
-
if (!
|
|
1412
|
-
|
|
1429
|
+
const dir = path12.dirname(configPath);
|
|
1430
|
+
if (!fs10.existsSync(dir)) {
|
|
1431
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
1413
1432
|
}
|
|
1414
1433
|
const content = serializeMCPConfig(config);
|
|
1415
|
-
|
|
1434
|
+
fs10.writeFileSync(configPath, content);
|
|
1416
1435
|
}
|
|
1417
1436
|
function parseMCPConfig(content) {
|
|
1418
1437
|
try {
|
|
@@ -1501,16 +1520,16 @@ function getProjectPermissions(config, name, projectPath) {
|
|
|
1501
1520
|
}
|
|
1502
1521
|
function cleanStaleProjects(config) {
|
|
1503
1522
|
const rrceHome = getEffectiveGlobalPath();
|
|
1504
|
-
const globalWorkspacesDir =
|
|
1523
|
+
const globalWorkspacesDir = path12.join(rrceHome, "workspaces");
|
|
1505
1524
|
const validProjects = [];
|
|
1506
1525
|
const removed = [];
|
|
1507
1526
|
for (const project of config.projects) {
|
|
1508
1527
|
let exists = false;
|
|
1509
1528
|
if (project.path) {
|
|
1510
|
-
exists =
|
|
1529
|
+
exists = fs10.existsSync(project.path);
|
|
1511
1530
|
} else {
|
|
1512
|
-
const globalPath =
|
|
1513
|
-
exists =
|
|
1531
|
+
const globalPath = path12.join(globalWorkspacesDir, project.name);
|
|
1532
|
+
exists = fs10.existsSync(globalPath);
|
|
1514
1533
|
}
|
|
1515
1534
|
if (exists) {
|
|
1516
1535
|
validProjects.push(project);
|
|
@@ -1537,10 +1556,10 @@ var gitignore_exports = {};
|
|
|
1537
1556
|
__export(gitignore_exports, {
|
|
1538
1557
|
updateGitignore: () => updateGitignore
|
|
1539
1558
|
});
|
|
1540
|
-
import * as
|
|
1541
|
-
import * as
|
|
1559
|
+
import * as fs12 from "fs";
|
|
1560
|
+
import * as path14 from "path";
|
|
1542
1561
|
function updateGitignore(workspacePath, storageMode, tools) {
|
|
1543
|
-
const gitignorePath =
|
|
1562
|
+
const gitignorePath = path14.join(workspacePath, ".gitignore");
|
|
1544
1563
|
const entries = [];
|
|
1545
1564
|
if (storageMode === "workspace") {
|
|
1546
1565
|
entries.push(".rrce-workflow/");
|
|
@@ -1559,8 +1578,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
1559
1578
|
return false;
|
|
1560
1579
|
}
|
|
1561
1580
|
let existingContent = "";
|
|
1562
|
-
if (
|
|
1563
|
-
existingContent =
|
|
1581
|
+
if (fs12.existsSync(gitignorePath)) {
|
|
1582
|
+
existingContent = fs12.readFileSync(gitignorePath, "utf-8");
|
|
1564
1583
|
}
|
|
1565
1584
|
const sectionMarker = "# RRCE-Workflow Generated";
|
|
1566
1585
|
if (existingContent.includes(sectionMarker)) {
|
|
@@ -1571,7 +1590,7 @@ ${sectionMarker}
|
|
|
1571
1590
|
${entries.join("\n")}
|
|
1572
1591
|
`;
|
|
1573
1592
|
const updatedContent = existingContent.trimEnd() + newSection;
|
|
1574
|
-
|
|
1593
|
+
fs12.writeFileSync(gitignorePath, updatedContent);
|
|
1575
1594
|
return true;
|
|
1576
1595
|
}
|
|
1577
1596
|
var init_gitignore = __esm({
|
|
@@ -1581,12 +1600,12 @@ var init_gitignore = __esm({
|
|
|
1581
1600
|
});
|
|
1582
1601
|
|
|
1583
1602
|
// src/mcp/logger.ts
|
|
1584
|
-
import * as
|
|
1585
|
-
import * as
|
|
1603
|
+
import * as fs13 from "fs";
|
|
1604
|
+
import * as path15 from "path";
|
|
1586
1605
|
function getLogFilePath() {
|
|
1587
1606
|
const workspaceRoot = detectWorkspaceRoot();
|
|
1588
1607
|
const rrceHome = getEffectiveRRCEHome(workspaceRoot);
|
|
1589
|
-
return
|
|
1608
|
+
return path15.join(rrceHome, "mcp-server.log");
|
|
1590
1609
|
}
|
|
1591
1610
|
var Logger, logger;
|
|
1592
1611
|
var init_logger = __esm({
|
|
@@ -1617,11 +1636,11 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
1617
1636
|
}
|
|
1618
1637
|
logMessage += "\n";
|
|
1619
1638
|
try {
|
|
1620
|
-
const dir =
|
|
1621
|
-
if (!
|
|
1622
|
-
|
|
1639
|
+
const dir = path15.dirname(this.logPath);
|
|
1640
|
+
if (!fs13.existsSync(dir)) {
|
|
1641
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
1623
1642
|
}
|
|
1624
|
-
|
|
1643
|
+
fs13.appendFileSync(this.logPath, logMessage);
|
|
1625
1644
|
} catch (e) {
|
|
1626
1645
|
console.error(`[Logger Failure] Could not write to ${this.logPath}`, e);
|
|
1627
1646
|
console.error(logMessage);
|
|
@@ -1737,18 +1756,18 @@ var init_constants = __esm({
|
|
|
1737
1756
|
});
|
|
1738
1757
|
|
|
1739
1758
|
// src/mcp/resources/utils.ts
|
|
1740
|
-
import * as
|
|
1741
|
-
import * as
|
|
1759
|
+
import * as fs14 from "fs";
|
|
1760
|
+
import * as path16 from "path";
|
|
1742
1761
|
import ignore from "ignore";
|
|
1743
1762
|
function estimateTokens(text2) {
|
|
1744
1763
|
return Math.ceil(text2.length / 4);
|
|
1745
1764
|
}
|
|
1746
1765
|
function getScanContext(project, scanRoot) {
|
|
1747
|
-
const gitignorePath =
|
|
1748
|
-
const ig =
|
|
1766
|
+
const gitignorePath = path16.join(scanRoot, ".gitignore");
|
|
1767
|
+
const ig = fs14.existsSync(gitignorePath) ? ignore().add(fs14.readFileSync(gitignorePath, "utf-8")) : null;
|
|
1749
1768
|
const toPosixRelativePath = (absolutePath) => {
|
|
1750
|
-
const rel =
|
|
1751
|
-
return rel.split(
|
|
1769
|
+
const rel = path16.relative(scanRoot, absolutePath);
|
|
1770
|
+
return rel.split(path16.sep).join("/");
|
|
1752
1771
|
};
|
|
1753
1772
|
const isUnderGitDir = (absolutePath) => {
|
|
1754
1773
|
const rel = toPosixRelativePath(absolutePath);
|
|
@@ -1760,7 +1779,7 @@ function getScanContext(project, scanRoot) {
|
|
|
1760
1779
|
return ig.ignores(isDir ? `${rel}/` : rel);
|
|
1761
1780
|
};
|
|
1762
1781
|
const shouldSkipEntryDir = (absolutePath) => {
|
|
1763
|
-
const dirName =
|
|
1782
|
+
const dirName = path16.basename(absolutePath);
|
|
1764
1783
|
if (dirName === ".git") return true;
|
|
1765
1784
|
if (SKIP_DIRS.includes(dirName)) return true;
|
|
1766
1785
|
if (isIgnoredByGitignore(absolutePath, true)) return true;
|
|
@@ -1781,7 +1800,7 @@ var init_utils2 = __esm({
|
|
|
1781
1800
|
});
|
|
1782
1801
|
|
|
1783
1802
|
// src/mcp/resources/paths.ts
|
|
1784
|
-
import * as
|
|
1803
|
+
import * as fs15 from "fs";
|
|
1785
1804
|
function resolveProjectPaths(project, pathInput) {
|
|
1786
1805
|
const config = loadMCPConfig();
|
|
1787
1806
|
let workspaceRoot = pathInput;
|
|
@@ -1809,8 +1828,8 @@ function resolveProjectPaths(project, pathInput) {
|
|
|
1809
1828
|
mode = "global";
|
|
1810
1829
|
} else {
|
|
1811
1830
|
mode = "workspace";
|
|
1812
|
-
if (
|
|
1813
|
-
const content =
|
|
1831
|
+
if (fs15.existsSync(configFilePath)) {
|
|
1832
|
+
const content = fs15.readFileSync(configFilePath, "utf-8");
|
|
1814
1833
|
if (content.includes("mode: global")) mode = "global";
|
|
1815
1834
|
if (content.includes("mode: workspace")) mode = "workspace";
|
|
1816
1835
|
}
|
|
@@ -1838,8 +1857,8 @@ var init_paths2 = __esm({
|
|
|
1838
1857
|
});
|
|
1839
1858
|
|
|
1840
1859
|
// src/mcp/resources/projects.ts
|
|
1841
|
-
import * as
|
|
1842
|
-
import * as
|
|
1860
|
+
import * as fs16 from "fs";
|
|
1861
|
+
import * as path17 from "path";
|
|
1843
1862
|
function getExposedProjects() {
|
|
1844
1863
|
const config = loadMCPConfig();
|
|
1845
1864
|
const knownProjects = config.projects.filter((p) => !!p.path).map((p) => ({ name: p.name, path: p.path }));
|
|
@@ -1848,10 +1867,10 @@ function getExposedProjects() {
|
|
|
1848
1867
|
const potentialProjects = [...allProjects];
|
|
1849
1868
|
if (activeProject) {
|
|
1850
1869
|
let cfgContent = null;
|
|
1851
|
-
if (
|
|
1852
|
-
cfgContent =
|
|
1853
|
-
} else if (
|
|
1854
|
-
cfgContent =
|
|
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");
|
|
1855
1874
|
}
|
|
1856
1875
|
if (cfgContent) {
|
|
1857
1876
|
if (cfgContent.includes("linked_projects:")) {
|
|
@@ -1909,15 +1928,15 @@ function getProjectContext(projectName) {
|
|
|
1909
1928
|
if (!project.knowledgePath) {
|
|
1910
1929
|
return null;
|
|
1911
1930
|
}
|
|
1912
|
-
const contextPath =
|
|
1913
|
-
if (!
|
|
1931
|
+
const contextPath = path17.join(project.knowledgePath, "project-context.md");
|
|
1932
|
+
if (!fs16.existsSync(contextPath)) {
|
|
1914
1933
|
return null;
|
|
1915
1934
|
}
|
|
1916
|
-
return
|
|
1935
|
+
return fs16.readFileSync(contextPath, "utf-8");
|
|
1917
1936
|
}
|
|
1918
1937
|
function getCodeIndexPath(project) {
|
|
1919
1938
|
const scanRoot = project.path || project.dataPath;
|
|
1920
|
-
return
|
|
1939
|
+
return path17.join(project.knowledgePath || path17.join(scanRoot, ".rrce-workflow", "knowledge"), "code-embeddings.json");
|
|
1921
1940
|
}
|
|
1922
1941
|
var init_projects = __esm({
|
|
1923
1942
|
"src/mcp/resources/projects.ts"() {
|
|
@@ -1930,8 +1949,8 @@ var init_projects = __esm({
|
|
|
1930
1949
|
});
|
|
1931
1950
|
|
|
1932
1951
|
// src/mcp/resources/tasks.ts
|
|
1933
|
-
import * as
|
|
1934
|
-
import * as
|
|
1952
|
+
import * as fs17 from "fs";
|
|
1953
|
+
import * as path18 from "path";
|
|
1935
1954
|
import * as os3 from "os";
|
|
1936
1955
|
import * as crypto from "crypto";
|
|
1937
1956
|
function getProjectTasks(projectName) {
|
|
@@ -1945,18 +1964,18 @@ function getProjectTasks(projectName) {
|
|
|
1945
1964
|
if (!permissions.tasks) {
|
|
1946
1965
|
return [];
|
|
1947
1966
|
}
|
|
1948
|
-
if (!project.tasksPath || !
|
|
1967
|
+
if (!project.tasksPath || !fs17.existsSync(project.tasksPath)) {
|
|
1949
1968
|
return [];
|
|
1950
1969
|
}
|
|
1951
1970
|
const tasks = [];
|
|
1952
1971
|
try {
|
|
1953
|
-
const taskDirs =
|
|
1972
|
+
const taskDirs = fs17.readdirSync(project.tasksPath, { withFileTypes: true });
|
|
1954
1973
|
for (const dir of taskDirs) {
|
|
1955
1974
|
if (!dir.isDirectory()) continue;
|
|
1956
|
-
const metaPath =
|
|
1957
|
-
if (
|
|
1975
|
+
const metaPath = path18.join(project.tasksPath, dir.name, "meta.json");
|
|
1976
|
+
if (fs17.existsSync(metaPath)) {
|
|
1958
1977
|
try {
|
|
1959
|
-
const meta = JSON.parse(
|
|
1978
|
+
const meta = JSON.parse(fs17.readFileSync(metaPath, "utf-8"));
|
|
1960
1979
|
tasks.push(meta);
|
|
1961
1980
|
} catch (err) {
|
|
1962
1981
|
logger.error(`[getProjectTasks] Failed to parse meta.json in ${dir.name}`, err);
|
|
@@ -1973,10 +1992,10 @@ function getTask(projectName, taskSlug) {
|
|
|
1973
1992
|
const projects = projectService.scan();
|
|
1974
1993
|
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
|
|
1975
1994
|
if (!project || !project.tasksPath) return null;
|
|
1976
|
-
const metaPath =
|
|
1977
|
-
if (!
|
|
1995
|
+
const metaPath = path18.join(project.tasksPath, taskSlug, "meta.json");
|
|
1996
|
+
if (!fs17.existsSync(metaPath)) return null;
|
|
1978
1997
|
try {
|
|
1979
|
-
return JSON.parse(
|
|
1998
|
+
return JSON.parse(fs17.readFileSync(metaPath, "utf-8"));
|
|
1980
1999
|
} catch (err) {
|
|
1981
2000
|
logger.error(`[getTask] Failed to parse meta.json for task ${taskSlug}`, err);
|
|
1982
2001
|
return null;
|
|
@@ -1989,26 +2008,26 @@ async function createTask(projectName, taskSlug, taskData) {
|
|
|
1989
2008
|
if (!project || !project.tasksPath) {
|
|
1990
2009
|
throw new Error(`Project '${projectName}' not found or not configured with a tasks path.`);
|
|
1991
2010
|
}
|
|
1992
|
-
const taskDir =
|
|
1993
|
-
if (
|
|
2011
|
+
const taskDir = path18.join(project.tasksPath, taskSlug);
|
|
2012
|
+
if (fs17.existsSync(taskDir)) {
|
|
1994
2013
|
throw new Error(`Task with slug '${taskSlug}' already exists.`);
|
|
1995
2014
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
const rrceHome = process.env.RRCE_HOME ||
|
|
2002
|
-
const templatePath =
|
|
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");
|
|
2003
2022
|
let meta = {
|
|
2004
2023
|
task_id: crypto.randomUUID(),
|
|
2005
2024
|
task_slug: taskSlug,
|
|
2006
2025
|
status: "draft",
|
|
2007
2026
|
agents: {}
|
|
2008
2027
|
};
|
|
2009
|
-
if (
|
|
2028
|
+
if (fs17.existsSync(templatePath)) {
|
|
2010
2029
|
try {
|
|
2011
|
-
const template = JSON.parse(
|
|
2030
|
+
const template = JSON.parse(fs17.readFileSync(templatePath, "utf-8"));
|
|
2012
2031
|
meta = { ...template, ...meta };
|
|
2013
2032
|
} catch (e) {
|
|
2014
2033
|
logger.error("Failed to load meta template", e);
|
|
@@ -2022,8 +2041,8 @@ async function createTask(projectName, taskSlug, taskData) {
|
|
|
2022
2041
|
hash: project.name
|
|
2023
2042
|
};
|
|
2024
2043
|
Object.assign(meta, taskData);
|
|
2025
|
-
const metaPath =
|
|
2026
|
-
|
|
2044
|
+
const metaPath = path18.join(taskDir, "meta.json");
|
|
2045
|
+
fs17.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
|
|
2027
2046
|
return meta;
|
|
2028
2047
|
}
|
|
2029
2048
|
async function updateTask(projectName, taskSlug, taskData) {
|
|
@@ -2042,8 +2061,8 @@ async function updateTask(projectName, taskSlug, taskData) {
|
|
|
2042
2061
|
const projects = projectService.scan();
|
|
2043
2062
|
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
|
|
2044
2063
|
if (!project || !project.tasksPath) return null;
|
|
2045
|
-
const metaPath =
|
|
2046
|
-
|
|
2064
|
+
const metaPath = path18.join(project.tasksPath, taskSlug, "meta.json");
|
|
2065
|
+
fs17.writeFileSync(metaPath, JSON.stringify(updatedMeta, null, 2));
|
|
2047
2066
|
return updatedMeta;
|
|
2048
2067
|
}
|
|
2049
2068
|
function deleteTask(projectName, taskSlug) {
|
|
@@ -2051,12 +2070,12 @@ function deleteTask(projectName, taskSlug) {
|
|
|
2051
2070
|
const projects = projectService.scan();
|
|
2052
2071
|
const project = projects.find((p) => p.name === projectName && isProjectExposed(config, p.name, p.sourcePath || p.path));
|
|
2053
2072
|
if (!project || !project.tasksPath) return false;
|
|
2054
|
-
const taskDir =
|
|
2055
|
-
if (!
|
|
2056
|
-
if (
|
|
2057
|
-
|
|
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 });
|
|
2058
2077
|
} else {
|
|
2059
|
-
|
|
2078
|
+
fs17.rmdirSync(taskDir, { recursive: true });
|
|
2060
2079
|
}
|
|
2061
2080
|
return true;
|
|
2062
2081
|
}
|
|
@@ -2070,8 +2089,8 @@ var init_tasks = __esm({
|
|
|
2070
2089
|
});
|
|
2071
2090
|
|
|
2072
2091
|
// src/mcp/services/rag.ts
|
|
2073
|
-
import * as
|
|
2074
|
-
import * as
|
|
2092
|
+
import * as fs18 from "fs";
|
|
2093
|
+
import * as path19 from "path";
|
|
2075
2094
|
var INDEX_VERSION, DEFAULT_MODEL, RAGService;
|
|
2076
2095
|
var init_rag = __esm({
|
|
2077
2096
|
"src/mcp/services/rag.ts"() {
|
|
@@ -2125,9 +2144,9 @@ var init_rag = __esm({
|
|
|
2125
2144
|
*/
|
|
2126
2145
|
loadIndex() {
|
|
2127
2146
|
if (this.index) return;
|
|
2128
|
-
if (
|
|
2147
|
+
if (fs18.existsSync(this.indexPath)) {
|
|
2129
2148
|
try {
|
|
2130
|
-
const data =
|
|
2149
|
+
const data = fs18.readFileSync(this.indexPath, "utf-8");
|
|
2131
2150
|
this.index = JSON.parse(data);
|
|
2132
2151
|
logger.info(`[RAG] Loaded index from ${this.indexPath} with ${this.index?.chunks.length} chunks.`);
|
|
2133
2152
|
} catch (error) {
|
|
@@ -2153,11 +2172,11 @@ var init_rag = __esm({
|
|
|
2153
2172
|
saveIndex() {
|
|
2154
2173
|
if (!this.index) return;
|
|
2155
2174
|
try {
|
|
2156
|
-
const dir =
|
|
2157
|
-
if (!
|
|
2158
|
-
|
|
2175
|
+
const dir = path19.dirname(this.indexPath);
|
|
2176
|
+
if (!fs18.existsSync(dir)) {
|
|
2177
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
2159
2178
|
}
|
|
2160
|
-
|
|
2179
|
+
fs18.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
|
|
2161
2180
|
logger.info(`[RAG] Saved index to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
|
|
2162
2181
|
} catch (error) {
|
|
2163
2182
|
logger.error(`[RAG] Failed to save index to ${this.indexPath}`, error);
|
|
@@ -2168,13 +2187,13 @@ var init_rag = __esm({
|
|
|
2168
2187
|
*/
|
|
2169
2188
|
saveIndexAtomic() {
|
|
2170
2189
|
if (!this.index) return;
|
|
2171
|
-
const dir =
|
|
2172
|
-
if (!
|
|
2173
|
-
|
|
2190
|
+
const dir = path19.dirname(this.indexPath);
|
|
2191
|
+
if (!fs18.existsSync(dir)) {
|
|
2192
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
2174
2193
|
}
|
|
2175
2194
|
const tmpPath = `${this.indexPath}.tmp`;
|
|
2176
|
-
|
|
2177
|
-
|
|
2195
|
+
fs18.writeFileSync(tmpPath, JSON.stringify(this.index, null, 2));
|
|
2196
|
+
fs18.renameSync(tmpPath, this.indexPath);
|
|
2178
2197
|
}
|
|
2179
2198
|
/**
|
|
2180
2199
|
* Save index only if enough time passed since last save
|
|
@@ -2707,10 +2726,10 @@ var init_context_extractor = __esm({
|
|
|
2707
2726
|
});
|
|
2708
2727
|
|
|
2709
2728
|
// src/mcp/services/dependency-graph.ts
|
|
2710
|
-
import * as
|
|
2711
|
-
import * as
|
|
2729
|
+
import * as fs19 from "fs";
|
|
2730
|
+
import * as path20 from "path";
|
|
2712
2731
|
function parseImports(filePath, content) {
|
|
2713
|
-
const ext =
|
|
2732
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
2714
2733
|
const language = getLanguageFromExtension(ext);
|
|
2715
2734
|
const edges = [];
|
|
2716
2735
|
const patterns = IMPORT_PATTERNS[language] || IMPORT_PATTERNS.javascript || [];
|
|
@@ -2740,20 +2759,20 @@ function parseImports(filePath, content) {
|
|
|
2740
2759
|
return edges;
|
|
2741
2760
|
}
|
|
2742
2761
|
function resolveImport(fromFile, importPath, language) {
|
|
2743
|
-
const fromDir =
|
|
2762
|
+
const fromDir = path20.dirname(fromFile);
|
|
2744
2763
|
if (importPath.startsWith(".")) {
|
|
2745
|
-
const candidates = generateCandidates(
|
|
2764
|
+
const candidates = generateCandidates(path20.resolve(fromDir, importPath), language);
|
|
2746
2765
|
for (const candidate of candidates) {
|
|
2747
|
-
if (
|
|
2766
|
+
if (fs19.existsSync(candidate)) {
|
|
2748
2767
|
return { path: candidate, isResolved: true };
|
|
2749
2768
|
}
|
|
2750
2769
|
}
|
|
2751
|
-
return { path:
|
|
2770
|
+
return { path: path20.resolve(fromDir, importPath), isResolved: false };
|
|
2752
2771
|
}
|
|
2753
2772
|
if (importPath.startsWith("/")) {
|
|
2754
2773
|
const candidates = generateCandidates(importPath, language);
|
|
2755
2774
|
for (const candidate of candidates) {
|
|
2756
|
-
if (
|
|
2775
|
+
if (fs19.existsSync(candidate)) {
|
|
2757
2776
|
return { path: candidate, isResolved: true };
|
|
2758
2777
|
}
|
|
2759
2778
|
}
|
|
@@ -2763,7 +2782,7 @@ function resolveImport(fromFile, importPath, language) {
|
|
|
2763
2782
|
}
|
|
2764
2783
|
function generateCandidates(basePath, language) {
|
|
2765
2784
|
const candidates = [];
|
|
2766
|
-
if (
|
|
2785
|
+
if (path20.extname(basePath)) {
|
|
2767
2786
|
candidates.push(basePath);
|
|
2768
2787
|
}
|
|
2769
2788
|
switch (language) {
|
|
@@ -2878,18 +2897,18 @@ async function scanProjectDependencies(projectRoot, options = {}) {
|
|
|
2878
2897
|
const files = [];
|
|
2879
2898
|
function scanDir(dir) {
|
|
2880
2899
|
try {
|
|
2881
|
-
const entries =
|
|
2900
|
+
const entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
2882
2901
|
for (const entry of entries) {
|
|
2883
|
-
const fullPath =
|
|
2902
|
+
const fullPath = path20.join(dir, entry.name);
|
|
2884
2903
|
if (entry.isDirectory()) {
|
|
2885
2904
|
if (!skipDirs.includes(entry.name) && !entry.name.startsWith(".")) {
|
|
2886
2905
|
scanDir(fullPath);
|
|
2887
2906
|
}
|
|
2888
2907
|
} else if (entry.isFile()) {
|
|
2889
|
-
const ext =
|
|
2908
|
+
const ext = path20.extname(entry.name).toLowerCase();
|
|
2890
2909
|
if (extensions.includes(ext)) {
|
|
2891
2910
|
try {
|
|
2892
|
-
const content =
|
|
2911
|
+
const content = fs19.readFileSync(fullPath, "utf-8");
|
|
2893
2912
|
files.push({ path: fullPath, content });
|
|
2894
2913
|
} catch {
|
|
2895
2914
|
}
|
|
@@ -3186,9 +3205,53 @@ var init_symbol_extractor = __esm({
|
|
|
3186
3205
|
}
|
|
3187
3206
|
});
|
|
3188
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
|
+
|
|
3189
3252
|
// src/mcp/resources/search.ts
|
|
3190
|
-
import * as
|
|
3191
|
-
import * as
|
|
3253
|
+
import * as fs20 from "fs";
|
|
3254
|
+
import * as path21 from "path";
|
|
3192
3255
|
async function searchCode(query, projectFilter, limit = 10, options) {
|
|
3193
3256
|
const config = loadMCPConfig();
|
|
3194
3257
|
const projects = getExposedProjects();
|
|
@@ -3197,8 +3260,7 @@ async function searchCode(query, projectFilter, limit = 10, options) {
|
|
|
3197
3260
|
if (projectFilter && project.name !== projectFilter) continue;
|
|
3198
3261
|
const permissions = getProjectPermissions(config, project.name, project.sourcePath || project.path);
|
|
3199
3262
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
3200
|
-
const
|
|
3201
|
-
const advisoryMessage2 = indexingInProgress2 ? "Indexing in progress; results may be stale/incomplete." : void 0;
|
|
3263
|
+
const { indexingInProgress, advisoryMessage } = getSearchAdvisory(project.name);
|
|
3202
3264
|
const projConfig = findProjectConfig(config, { name: project.name, path: project.sourcePath || project.path });
|
|
3203
3265
|
const useRAG = projConfig?.semanticSearch?.enabled;
|
|
3204
3266
|
if (!useRAG) {
|
|
@@ -3207,7 +3269,7 @@ async function searchCode(query, projectFilter, limit = 10, options) {
|
|
|
3207
3269
|
}
|
|
3208
3270
|
try {
|
|
3209
3271
|
const codeIndexPath = getCodeIndexPath(project);
|
|
3210
|
-
if (!
|
|
3272
|
+
if (!fs20.existsSync(codeIndexPath)) {
|
|
3211
3273
|
logger.debug(`[searchCode] Code index not found for project '${project.name}'`);
|
|
3212
3274
|
continue;
|
|
3213
3275
|
}
|
|
@@ -3217,15 +3279,13 @@ async function searchCode(query, projectFilter, limit = 10, options) {
|
|
|
3217
3279
|
const codeChunk = r;
|
|
3218
3280
|
results.push({
|
|
3219
3281
|
project: project.name,
|
|
3220
|
-
file:
|
|
3282
|
+
file: path21.relative(project.sourcePath || project.path || "", codeChunk.filePath),
|
|
3221
3283
|
snippet: codeChunk.content,
|
|
3222
3284
|
lineStart: codeChunk.lineStart ?? 1,
|
|
3223
3285
|
lineEnd: codeChunk.lineEnd ?? 1,
|
|
3224
3286
|
context: codeChunk.context,
|
|
3225
3287
|
language: codeChunk.language,
|
|
3226
|
-
score: codeChunk.score
|
|
3227
|
-
indexingInProgress: indexingInProgress2 || void 0,
|
|
3228
|
-
advisoryMessage: advisoryMessage2
|
|
3288
|
+
score: codeChunk.score
|
|
3229
3289
|
});
|
|
3230
3290
|
}
|
|
3231
3291
|
} catch (e) {
|
|
@@ -3237,49 +3297,32 @@ async function searchCode(query, projectFilter, limit = 10, options) {
|
|
|
3237
3297
|
if (options?.min_score !== void 0 && options.min_score > 0) {
|
|
3238
3298
|
filteredResults = results.filter((r) => r.score >= options.min_score);
|
|
3239
3299
|
}
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
const resultTokens = estimateTokens(result.snippet + (result.context || ""));
|
|
3247
|
-
if (tokenCount + resultTokens > options.max_tokens) {
|
|
3248
|
-
truncated = true;
|
|
3249
|
-
break;
|
|
3250
|
-
}
|
|
3251
|
-
budgetedResults.push(result);
|
|
3252
|
-
tokenCount += resultTokens;
|
|
3253
|
-
}
|
|
3254
|
-
limitedResults = budgetedResults;
|
|
3255
|
-
} else {
|
|
3256
|
-
tokenCount = limitedResults.reduce((sum, r) => sum + estimateTokens(r.snippet + (r.context || "")), 0);
|
|
3257
|
-
}
|
|
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
|
+
);
|
|
3258
3306
|
let indexAgeSeconds;
|
|
3259
3307
|
let lastIndexedAt;
|
|
3260
|
-
let
|
|
3261
|
-
let
|
|
3308
|
+
let indexingInProgressGlobal;
|
|
3309
|
+
let advisoryMessageGlobal;
|
|
3262
3310
|
if (projectFilter) {
|
|
3263
|
-
const
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
lastIndexedAt = new Date(progress.completedAt).toISOString();
|
|
3270
|
-
indexAgeSeconds = Math.floor((Date.now() - progress.completedAt) / 1e3);
|
|
3271
|
-
}
|
|
3272
|
-
}
|
|
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;
|
|
3273
3317
|
}
|
|
3274
|
-
const cleanResults = limitedResults.map(({ indexingInProgress: _, advisoryMessage: __, ...rest }) => rest);
|
|
3275
3318
|
return {
|
|
3276
|
-
results:
|
|
3319
|
+
results: budgetedResults,
|
|
3277
3320
|
token_count: tokenCount,
|
|
3278
3321
|
truncated,
|
|
3279
3322
|
index_age_seconds: indexAgeSeconds,
|
|
3280
3323
|
last_indexed_at: lastIndexedAt,
|
|
3281
|
-
indexingInProgress,
|
|
3282
|
-
advisoryMessage
|
|
3324
|
+
indexingInProgress: indexingInProgressGlobal,
|
|
3325
|
+
advisoryMessage: advisoryMessageGlobal
|
|
3283
3326
|
};
|
|
3284
3327
|
}
|
|
3285
3328
|
async function searchKnowledge(query, projectFilter, options) {
|
|
@@ -3291,24 +3334,20 @@ async function searchKnowledge(query, projectFilter, options) {
|
|
|
3291
3334
|
if (projectFilter && project.name !== projectFilter) continue;
|
|
3292
3335
|
const permissions = getProjectPermissions(config, project.name, project.sourcePath || project.path);
|
|
3293
3336
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
3294
|
-
const
|
|
3295
|
-
const advisoryMessage2 = indexingInProgress2 ? "Indexing in progress; results may be stale/incomplete." : void 0;
|
|
3337
|
+
const { indexingInProgress, advisoryMessage } = getSearchAdvisory(project.name);
|
|
3296
3338
|
const projConfig = findProjectConfig(config, { name: project.name, path: project.sourcePath || project.path });
|
|
3297
3339
|
const useRAG = projConfig?.semanticSearch?.enabled;
|
|
3298
3340
|
if (useRAG) {
|
|
3299
|
-
logger.info(`[RAG] Using semantic search for project '${project.name}'`);
|
|
3300
3341
|
try {
|
|
3301
|
-
const indexPath =
|
|
3342
|
+
const indexPath = path21.join(project.knowledgePath, "embeddings.json");
|
|
3302
3343
|
const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
|
|
3303
3344
|
const ragResults = await rag.search(query, 5);
|
|
3304
3345
|
for (const r of ragResults) {
|
|
3305
3346
|
results.push({
|
|
3306
3347
|
project: project.name,
|
|
3307
|
-
file:
|
|
3348
|
+
file: path21.relative(project.knowledgePath, r.filePath),
|
|
3308
3349
|
matches: [r.content],
|
|
3309
|
-
score: r.score
|
|
3310
|
-
indexingInProgress: indexingInProgress2 || void 0,
|
|
3311
|
-
advisoryMessage: advisoryMessage2
|
|
3350
|
+
score: r.score
|
|
3312
3351
|
});
|
|
3313
3352
|
}
|
|
3314
3353
|
continue;
|
|
@@ -3317,11 +3356,11 @@ async function searchKnowledge(query, projectFilter, options) {
|
|
|
3317
3356
|
}
|
|
3318
3357
|
}
|
|
3319
3358
|
try {
|
|
3320
|
-
const files =
|
|
3359
|
+
const files = fs20.readdirSync(project.knowledgePath);
|
|
3321
3360
|
for (const file of files) {
|
|
3322
3361
|
if (!file.endsWith(".md")) continue;
|
|
3323
|
-
const filePath =
|
|
3324
|
-
const content =
|
|
3362
|
+
const filePath = path21.join(project.knowledgePath, file);
|
|
3363
|
+
const content = fs20.readFileSync(filePath, "utf-8");
|
|
3325
3364
|
const lines = content.split("\n");
|
|
3326
3365
|
const matches = [];
|
|
3327
3366
|
for (const line of lines) {
|
|
@@ -3333,10 +3372,7 @@ async function searchKnowledge(query, projectFilter, options) {
|
|
|
3333
3372
|
results.push({
|
|
3334
3373
|
project: project.name,
|
|
3335
3374
|
file,
|
|
3336
|
-
matches: matches.slice(0, 5)
|
|
3337
|
-
// Limit to 5 matches per file
|
|
3338
|
-
indexingInProgress: indexingInProgress2 || void 0,
|
|
3339
|
-
advisoryMessage: advisoryMessage2
|
|
3375
|
+
matches: matches.slice(0, 5)
|
|
3340
3376
|
});
|
|
3341
3377
|
}
|
|
3342
3378
|
}
|
|
@@ -3349,48 +3385,31 @@ async function searchKnowledge(query, projectFilter, options) {
|
|
|
3349
3385
|
filteredResults = results.filter((r) => (r.score ?? 1) >= options.min_score);
|
|
3350
3386
|
}
|
|
3351
3387
|
filteredResults.sort((a, b) => (b.score ?? 1) - (a.score ?? 1));
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
for (const result of filteredResults) {
|
|
3358
|
-
const resultTokens = estimateTokens(result.matches.join("\n"));
|
|
3359
|
-
if (tokenCount + resultTokens > options.max_tokens) {
|
|
3360
|
-
truncated = true;
|
|
3361
|
-
break;
|
|
3362
|
-
}
|
|
3363
|
-
budgetedResults.push(result);
|
|
3364
|
-
tokenCount += resultTokens;
|
|
3365
|
-
}
|
|
3366
|
-
} else {
|
|
3367
|
-
tokenCount = filteredResults.reduce((sum, r) => sum + estimateTokens(r.matches.join("\n")), 0);
|
|
3368
|
-
}
|
|
3388
|
+
const { budgetedResults, truncated, tokenCount } = applyTokenBudget(
|
|
3389
|
+
filteredResults,
|
|
3390
|
+
options?.max_tokens,
|
|
3391
|
+
(r) => r.matches.join("\n")
|
|
3392
|
+
);
|
|
3369
3393
|
let indexAgeSeconds;
|
|
3370
3394
|
let lastIndexedAt;
|
|
3371
|
-
let
|
|
3372
|
-
let
|
|
3395
|
+
let indexingInProgressGlobal;
|
|
3396
|
+
let advisoryMessageGlobal;
|
|
3373
3397
|
if (projectFilter) {
|
|
3374
|
-
const
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
lastIndexedAt = new Date(progress.completedAt).toISOString();
|
|
3381
|
-
indexAgeSeconds = Math.floor((Date.now() - progress.completedAt) / 1e3);
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
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;
|
|
3384
3404
|
}
|
|
3385
|
-
const cleanResults = budgetedResults.map(({ indexingInProgress: _, advisoryMessage: __, ...rest }) => rest);
|
|
3386
3405
|
return {
|
|
3387
|
-
results:
|
|
3406
|
+
results: budgetedResults,
|
|
3388
3407
|
token_count: tokenCount,
|
|
3389
3408
|
truncated,
|
|
3390
3409
|
index_age_seconds: indexAgeSeconds,
|
|
3391
3410
|
last_indexed_at: lastIndexedAt,
|
|
3392
|
-
indexingInProgress,
|
|
3393
|
-
advisoryMessage
|
|
3411
|
+
indexingInProgress: indexingInProgressGlobal,
|
|
3412
|
+
advisoryMessage: advisoryMessageGlobal
|
|
3394
3413
|
};
|
|
3395
3414
|
}
|
|
3396
3415
|
async function findRelatedFiles2(filePath, projectName, options = {}) {
|
|
@@ -3408,10 +3427,10 @@ async function findRelatedFiles2(filePath, projectName, options = {}) {
|
|
|
3408
3427
|
}
|
|
3409
3428
|
const projectRoot = project.sourcePath || project.path || "";
|
|
3410
3429
|
let absoluteFilePath = filePath;
|
|
3411
|
-
if (!
|
|
3412
|
-
absoluteFilePath =
|
|
3430
|
+
if (!path21.isAbsolute(filePath)) {
|
|
3431
|
+
absoluteFilePath = path21.resolve(projectRoot, filePath);
|
|
3413
3432
|
}
|
|
3414
|
-
if (!
|
|
3433
|
+
if (!fs20.existsSync(absoluteFilePath)) {
|
|
3415
3434
|
return {
|
|
3416
3435
|
success: false,
|
|
3417
3436
|
file: filePath,
|
|
@@ -3428,13 +3447,13 @@ async function findRelatedFiles2(filePath, projectName, options = {}) {
|
|
|
3428
3447
|
depth: options.depth ?? 1
|
|
3429
3448
|
});
|
|
3430
3449
|
const relationships = related.map((r) => ({
|
|
3431
|
-
file:
|
|
3450
|
+
file: path21.relative(projectRoot, r.file),
|
|
3432
3451
|
relationship: r.relationship,
|
|
3433
3452
|
importPath: r.importPath
|
|
3434
3453
|
}));
|
|
3435
3454
|
return {
|
|
3436
3455
|
success: true,
|
|
3437
|
-
file:
|
|
3456
|
+
file: path21.relative(projectRoot, absoluteFilePath),
|
|
3438
3457
|
project: projectName,
|
|
3439
3458
|
relationships
|
|
3440
3459
|
};
|
|
@@ -3462,7 +3481,7 @@ async function searchSymbols2(name, projectName, options = {}) {
|
|
|
3462
3481
|
};
|
|
3463
3482
|
}
|
|
3464
3483
|
const projectRoot = project.sourcePath || project.path || "";
|
|
3465
|
-
if (!
|
|
3484
|
+
if (!fs20.existsSync(projectRoot)) {
|
|
3466
3485
|
return {
|
|
3467
3486
|
success: false,
|
|
3468
3487
|
project: projectName,
|
|
@@ -3473,14 +3492,14 @@ async function searchSymbols2(name, projectName, options = {}) {
|
|
|
3473
3492
|
try {
|
|
3474
3493
|
const codeFiles = [];
|
|
3475
3494
|
const scanDir = (dir) => {
|
|
3476
|
-
const entries =
|
|
3495
|
+
const entries = fs20.readdirSync(dir, { withFileTypes: true });
|
|
3477
3496
|
for (const entry of entries) {
|
|
3478
|
-
const fullPath =
|
|
3497
|
+
const fullPath = path21.join(dir, entry.name);
|
|
3479
3498
|
if (entry.isDirectory()) {
|
|
3480
3499
|
if (SKIP_DIRS.includes(entry.name)) continue;
|
|
3481
3500
|
scanDir(fullPath);
|
|
3482
3501
|
} else if (entry.isFile()) {
|
|
3483
|
-
const ext =
|
|
3502
|
+
const ext = path21.extname(entry.name).toLowerCase();
|
|
3484
3503
|
if (CODE_EXTENSIONS.includes(ext)) {
|
|
3485
3504
|
codeFiles.push(fullPath);
|
|
3486
3505
|
}
|
|
@@ -3491,7 +3510,7 @@ async function searchSymbols2(name, projectName, options = {}) {
|
|
|
3491
3510
|
const symbolResults = [];
|
|
3492
3511
|
for (const file of codeFiles.slice(0, 500)) {
|
|
3493
3512
|
try {
|
|
3494
|
-
const content =
|
|
3513
|
+
const content = fs20.readFileSync(file, "utf-8");
|
|
3495
3514
|
const result = extractSymbols(content, file);
|
|
3496
3515
|
symbolResults.push(result);
|
|
3497
3516
|
} catch (e) {
|
|
@@ -3506,7 +3525,7 @@ async function searchSymbols2(name, projectName, options = {}) {
|
|
|
3506
3525
|
const results = matches.map((m) => ({
|
|
3507
3526
|
name: m.name,
|
|
3508
3527
|
type: m.type,
|
|
3509
|
-
file:
|
|
3528
|
+
file: path21.relative(projectRoot, m.file),
|
|
3510
3529
|
line: m.line,
|
|
3511
3530
|
signature: m.signature,
|
|
3512
3531
|
exported: m.exported,
|
|
@@ -3539,24 +3558,24 @@ async function getFileSummary(filePath, projectName) {
|
|
|
3539
3558
|
}
|
|
3540
3559
|
const projectRoot = project.sourcePath || project.path || "";
|
|
3541
3560
|
let absolutePath = filePath;
|
|
3542
|
-
if (!
|
|
3543
|
-
absolutePath =
|
|
3561
|
+
if (!path21.isAbsolute(filePath)) {
|
|
3562
|
+
absolutePath = path21.resolve(projectRoot, filePath);
|
|
3544
3563
|
}
|
|
3545
|
-
if (!
|
|
3564
|
+
if (!fs20.existsSync(absolutePath)) {
|
|
3546
3565
|
return {
|
|
3547
3566
|
success: false,
|
|
3548
3567
|
message: `File not found: ${filePath}`
|
|
3549
3568
|
};
|
|
3550
3569
|
}
|
|
3551
3570
|
try {
|
|
3552
|
-
const stat =
|
|
3553
|
-
const content =
|
|
3571
|
+
const stat = fs20.statSync(absolutePath);
|
|
3572
|
+
const content = fs20.readFileSync(absolutePath, "utf-8");
|
|
3554
3573
|
const lines = content.split("\n");
|
|
3555
3574
|
const symbolResult = extractSymbols(content, absolutePath);
|
|
3556
3575
|
return {
|
|
3557
3576
|
success: true,
|
|
3558
3577
|
summary: {
|
|
3559
|
-
path:
|
|
3578
|
+
path: path21.relative(projectRoot, absolutePath),
|
|
3560
3579
|
language: symbolResult.language,
|
|
3561
3580
|
lines: lines.length,
|
|
3562
3581
|
size_bytes: stat.size,
|
|
@@ -3592,12 +3611,13 @@ var init_search = __esm({
|
|
|
3592
3611
|
init_projects();
|
|
3593
3612
|
init_utils2();
|
|
3594
3613
|
init_constants();
|
|
3614
|
+
init_search_utils();
|
|
3595
3615
|
}
|
|
3596
3616
|
});
|
|
3597
3617
|
|
|
3598
3618
|
// src/lib/drift-service.ts
|
|
3599
|
-
import * as
|
|
3600
|
-
import * as
|
|
3619
|
+
import * as fs21 from "fs";
|
|
3620
|
+
import * as path22 from "path";
|
|
3601
3621
|
import * as crypto2 from "crypto";
|
|
3602
3622
|
var DriftService;
|
|
3603
3623
|
var init_drift_service = __esm({
|
|
@@ -3606,26 +3626,26 @@ var init_drift_service = __esm({
|
|
|
3606
3626
|
DriftService = class {
|
|
3607
3627
|
static CHECKSUM_FILENAME = ".rrce-checksums.json";
|
|
3608
3628
|
static calculateHash(filePath) {
|
|
3609
|
-
const content =
|
|
3629
|
+
const content = fs21.readFileSync(filePath);
|
|
3610
3630
|
return crypto2.createHash("md5").update(content).digest("hex");
|
|
3611
3631
|
}
|
|
3612
3632
|
static getManifestPath(projectPath) {
|
|
3613
|
-
return
|
|
3633
|
+
return path22.join(projectPath, this.CHECKSUM_FILENAME);
|
|
3614
3634
|
}
|
|
3615
3635
|
static loadManifest(projectPath) {
|
|
3616
3636
|
const manifestPath = this.getManifestPath(projectPath);
|
|
3617
|
-
if (!
|
|
3637
|
+
if (!fs21.existsSync(manifestPath)) {
|
|
3618
3638
|
return {};
|
|
3619
3639
|
}
|
|
3620
3640
|
try {
|
|
3621
|
-
return JSON.parse(
|
|
3641
|
+
return JSON.parse(fs21.readFileSync(manifestPath, "utf8"));
|
|
3622
3642
|
} catch (e) {
|
|
3623
3643
|
return {};
|
|
3624
3644
|
}
|
|
3625
3645
|
}
|
|
3626
3646
|
static saveManifest(projectPath, manifest) {
|
|
3627
3647
|
const manifestPath = this.getManifestPath(projectPath);
|
|
3628
|
-
|
|
3648
|
+
fs21.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
3629
3649
|
}
|
|
3630
3650
|
/**
|
|
3631
3651
|
* Generates a manifest for the current state of files in the project
|
|
@@ -3633,9 +3653,9 @@ var init_drift_service = __esm({
|
|
|
3633
3653
|
static generateManifest(projectPath, files) {
|
|
3634
3654
|
const manifest = {};
|
|
3635
3655
|
for (const file of files) {
|
|
3636
|
-
const fullPath =
|
|
3637
|
-
if (
|
|
3638
|
-
const stats =
|
|
3656
|
+
const fullPath = path22.join(projectPath, file);
|
|
3657
|
+
if (fs21.existsSync(fullPath)) {
|
|
3658
|
+
const stats = fs21.statSync(fullPath);
|
|
3639
3659
|
manifest[file] = {
|
|
3640
3660
|
hash: this.calculateHash(fullPath),
|
|
3641
3661
|
mtime: stats.mtimeMs
|
|
@@ -3652,12 +3672,12 @@ var init_drift_service = __esm({
|
|
|
3652
3672
|
const modified = [];
|
|
3653
3673
|
const deleted = [];
|
|
3654
3674
|
for (const [relPath, entry] of Object.entries(manifest)) {
|
|
3655
|
-
const fullPath =
|
|
3656
|
-
if (!
|
|
3675
|
+
const fullPath = path22.join(projectPath, relPath);
|
|
3676
|
+
if (!fs21.existsSync(fullPath)) {
|
|
3657
3677
|
deleted.push(relPath);
|
|
3658
3678
|
continue;
|
|
3659
3679
|
}
|
|
3660
|
-
const stats =
|
|
3680
|
+
const stats = fs21.statSync(fullPath);
|
|
3661
3681
|
if (stats.mtimeMs === entry.mtime) {
|
|
3662
3682
|
continue;
|
|
3663
3683
|
}
|
|
@@ -3675,8 +3695,8 @@ var init_drift_service = __esm({
|
|
|
3675
3695
|
const manifest = this.loadManifest(projectPath);
|
|
3676
3696
|
const deleted = [];
|
|
3677
3697
|
for (const relPath of Object.keys(manifest)) {
|
|
3678
|
-
const fullPath =
|
|
3679
|
-
if (!
|
|
3698
|
+
const fullPath = path22.join(projectPath, relPath);
|
|
3699
|
+
if (!fs21.existsSync(fullPath)) {
|
|
3680
3700
|
deleted.push(relPath);
|
|
3681
3701
|
}
|
|
3682
3702
|
}
|
|
@@ -3712,8 +3732,8 @@ var init_drift_service = __esm({
|
|
|
3712
3732
|
});
|
|
3713
3733
|
|
|
3714
3734
|
// src/mcp/resources/indexing.ts
|
|
3715
|
-
import * as
|
|
3716
|
-
import * as
|
|
3735
|
+
import * as fs22 from "fs";
|
|
3736
|
+
import * as path23 from "path";
|
|
3717
3737
|
async function indexKnowledge(projectName, force = false, clean = false) {
|
|
3718
3738
|
const config = loadMCPConfig();
|
|
3719
3739
|
const projects = getExposedProjects();
|
|
@@ -3743,7 +3763,7 @@ async function indexKnowledge(projectName, force = false, clean = false) {
|
|
|
3743
3763
|
};
|
|
3744
3764
|
}
|
|
3745
3765
|
const scanRoot = project.sourcePath || project.path || project.dataPath;
|
|
3746
|
-
if (!
|
|
3766
|
+
if (!fs22.existsSync(scanRoot)) {
|
|
3747
3767
|
return {
|
|
3748
3768
|
state: "failed",
|
|
3749
3769
|
status: "failed",
|
|
@@ -3756,13 +3776,13 @@ async function indexKnowledge(projectName, force = false, clean = false) {
|
|
|
3756
3776
|
}
|
|
3757
3777
|
const runIndexing = async () => {
|
|
3758
3778
|
const { shouldSkipEntryDir, shouldSkipEntryFile } = getScanContext(project, scanRoot);
|
|
3759
|
-
const knowledgeDir = project.knowledgePath ||
|
|
3760
|
-
const indexPath =
|
|
3761
|
-
const codeIndexPath =
|
|
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");
|
|
3762
3782
|
if (clean) {
|
|
3763
3783
|
logger.info(`[RAG] Cleaning knowledge index for ${project.name}`);
|
|
3764
|
-
if (
|
|
3765
|
-
if (
|
|
3784
|
+
if (fs22.existsSync(indexPath)) fs22.unlinkSync(indexPath);
|
|
3785
|
+
if (fs22.existsSync(codeIndexPath)) fs22.unlinkSync(codeIndexPath);
|
|
3766
3786
|
}
|
|
3767
3787
|
const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
|
|
3768
3788
|
const rag = new RAGService(indexPath, model);
|
|
@@ -3773,14 +3793,14 @@ async function indexKnowledge(projectName, force = false, clean = false) {
|
|
|
3773
3793
|
let itemsTotal = 0;
|
|
3774
3794
|
let itemsDone = 0;
|
|
3775
3795
|
const preCount = (dir) => {
|
|
3776
|
-
const entries =
|
|
3796
|
+
const entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
3777
3797
|
for (const entry of entries) {
|
|
3778
|
-
const fullPath =
|
|
3798
|
+
const fullPath = path23.join(dir, entry.name);
|
|
3779
3799
|
if (entry.isDirectory()) {
|
|
3780
3800
|
if (shouldSkipEntryDir(fullPath)) continue;
|
|
3781
3801
|
preCount(fullPath);
|
|
3782
3802
|
} else if (entry.isFile()) {
|
|
3783
|
-
const ext =
|
|
3803
|
+
const ext = path23.extname(entry.name).toLowerCase();
|
|
3784
3804
|
if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
|
|
3785
3805
|
if (shouldSkipEntryFile(fullPath)) continue;
|
|
3786
3806
|
itemsTotal++;
|
|
@@ -3797,13 +3817,13 @@ async function indexKnowledge(projectName, force = false, clean = false) {
|
|
|
3797
3817
|
logger.info(`[RAG] ${project.name}: Detected ${deletedFiles.length} deleted files from manifest`);
|
|
3798
3818
|
}
|
|
3799
3819
|
for (const filePath of unique) {
|
|
3800
|
-
if (!
|
|
3801
|
-
const relFilePath = filePath.split(
|
|
3802
|
-
const relScanRoot = scanRoot.split(
|
|
3820
|
+
if (!path23.isAbsolute(filePath)) continue;
|
|
3821
|
+
const relFilePath = filePath.split(path23.sep).join("/");
|
|
3822
|
+
const relScanRoot = scanRoot.split(path23.sep).join("/");
|
|
3803
3823
|
const isInScanRoot = relFilePath === relScanRoot || relFilePath.startsWith(`${relScanRoot}/`);
|
|
3804
3824
|
if (!isInScanRoot) continue;
|
|
3805
3825
|
const isDeleted = deletedFiles.some((df) => filePath.endsWith(df));
|
|
3806
|
-
if (shouldSkipEntryFile(filePath) || isDeleted || !
|
|
3826
|
+
if (shouldSkipEntryFile(filePath) || isDeleted || !fs22.existsSync(filePath)) {
|
|
3807
3827
|
await rag.removeFile(filePath);
|
|
3808
3828
|
await codeRag.removeFile(filePath);
|
|
3809
3829
|
}
|
|
@@ -3811,21 +3831,21 @@ async function indexKnowledge(projectName, force = false, clean = false) {
|
|
|
3811
3831
|
};
|
|
3812
3832
|
await cleanupIgnoredFiles();
|
|
3813
3833
|
const scanDir = async (dir) => {
|
|
3814
|
-
const entries =
|
|
3834
|
+
const entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
3815
3835
|
for (const entry of entries) {
|
|
3816
|
-
const fullPath =
|
|
3836
|
+
const fullPath = path23.join(dir, entry.name);
|
|
3817
3837
|
if (entry.isDirectory()) {
|
|
3818
3838
|
if (shouldSkipEntryDir(fullPath)) continue;
|
|
3819
3839
|
await scanDir(fullPath);
|
|
3820
3840
|
} else if (entry.isFile()) {
|
|
3821
|
-
const ext =
|
|
3841
|
+
const ext = path23.extname(entry.name).toLowerCase();
|
|
3822
3842
|
if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
|
|
3823
3843
|
if (shouldSkipEntryFile(fullPath)) continue;
|
|
3824
3844
|
try {
|
|
3825
3845
|
indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
|
|
3826
|
-
const stat =
|
|
3846
|
+
const stat = fs22.statSync(fullPath);
|
|
3827
3847
|
const mtime = force ? void 0 : stat.mtimeMs;
|
|
3828
|
-
const content =
|
|
3848
|
+
const content = fs22.readFileSync(fullPath, "utf-8");
|
|
3829
3849
|
const wasIndexed = await rag.indexFile(fullPath, content, mtime);
|
|
3830
3850
|
if (wasIndexed) {
|
|
3831
3851
|
indexed++;
|
|
@@ -3902,7 +3922,7 @@ var init_indexing = __esm({
|
|
|
3902
3922
|
});
|
|
3903
3923
|
|
|
3904
3924
|
// src/mcp/resources/context.ts
|
|
3905
|
-
import * as
|
|
3925
|
+
import * as path24 from "path";
|
|
3906
3926
|
import * as os4 from "os";
|
|
3907
3927
|
function getContextPreamble() {
|
|
3908
3928
|
const activeProject = detectActiveProject();
|
|
@@ -3918,7 +3938,7 @@ If the above tools fail, ask the user for clarification.
|
|
|
3918
3938
|
---
|
|
3919
3939
|
`;
|
|
3920
3940
|
}
|
|
3921
|
-
const rrceHome = process.env.RRCE_HOME ||
|
|
3941
|
+
const rrceHome = process.env.RRCE_HOME || path24.join(os4.homedir(), ".rrce-workflow");
|
|
3922
3942
|
const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
3923
3943
|
const rrceData = activeProject.dataPath;
|
|
3924
3944
|
return `## System Context
|
|
@@ -4213,8 +4233,8 @@ var init_validation = __esm({
|
|
|
4213
4233
|
});
|
|
4214
4234
|
|
|
4215
4235
|
// src/mcp/resources/sessions.ts
|
|
4216
|
-
import * as
|
|
4217
|
-
import * as
|
|
4236
|
+
import * as fs23 from "fs";
|
|
4237
|
+
import * as path25 from "path";
|
|
4218
4238
|
function startSession(projectName, taskSlug, agent, phase) {
|
|
4219
4239
|
const config = loadMCPConfig();
|
|
4220
4240
|
const projects = projectService.scan();
|
|
@@ -4222,8 +4242,8 @@ function startSession(projectName, taskSlug, agent, phase) {
|
|
|
4222
4242
|
if (!project || !project.tasksPath) {
|
|
4223
4243
|
return { success: false, message: `Project '${projectName}' not found or not exposed.` };
|
|
4224
4244
|
}
|
|
4225
|
-
const taskDir =
|
|
4226
|
-
if (!
|
|
4245
|
+
const taskDir = path25.join(project.tasksPath, taskSlug);
|
|
4246
|
+
if (!fs23.existsSync(taskDir)) {
|
|
4227
4247
|
return { success: false, message: `Task '${taskSlug}' not found.` };
|
|
4228
4248
|
}
|
|
4229
4249
|
const session = {
|
|
@@ -4233,8 +4253,8 @@ function startSession(projectName, taskSlug, agent, phase) {
|
|
|
4233
4253
|
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4234
4254
|
heartbeat: (/* @__PURE__ */ new Date()).toISOString()
|
|
4235
4255
|
};
|
|
4236
|
-
const sessionPath =
|
|
4237
|
-
|
|
4256
|
+
const sessionPath = path25.join(taskDir, "session.json");
|
|
4257
|
+
fs23.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
|
|
4238
4258
|
return { success: true, message: `Session started for ${agent} agent on task '${taskSlug}' (phase: ${phase})` };
|
|
4239
4259
|
}
|
|
4240
4260
|
function endSession(projectName, taskSlug) {
|
|
@@ -4244,11 +4264,11 @@ function endSession(projectName, taskSlug) {
|
|
|
4244
4264
|
if (!project || !project.tasksPath) {
|
|
4245
4265
|
return { success: false, message: `Project '${projectName}' not found or not exposed.` };
|
|
4246
4266
|
}
|
|
4247
|
-
const sessionPath =
|
|
4248
|
-
if (!
|
|
4267
|
+
const sessionPath = path25.join(project.tasksPath, taskSlug, "session.json");
|
|
4268
|
+
if (!fs23.existsSync(sessionPath)) {
|
|
4249
4269
|
return { success: true, message: `No active session for task '${taskSlug}'.` };
|
|
4250
4270
|
}
|
|
4251
|
-
|
|
4271
|
+
fs23.unlinkSync(sessionPath);
|
|
4252
4272
|
return { success: true, message: `Session ended for task '${taskSlug}'.` };
|
|
4253
4273
|
}
|
|
4254
4274
|
function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
|
|
@@ -4258,9 +4278,9 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
|
|
|
4258
4278
|
if (!project || !project.tasksPath) {
|
|
4259
4279
|
return { success: false, message: `Project '${projectName}' not found or not exposed.` };
|
|
4260
4280
|
}
|
|
4261
|
-
const taskDir =
|
|
4262
|
-
if (!
|
|
4263
|
-
|
|
4281
|
+
const taskDir = path25.join(project.tasksPath, taskSlug);
|
|
4282
|
+
if (!fs23.existsSync(taskDir)) {
|
|
4283
|
+
fs23.mkdirSync(taskDir, { recursive: true });
|
|
4264
4284
|
}
|
|
4265
4285
|
const todos = {
|
|
4266
4286
|
phase,
|
|
@@ -4268,8 +4288,8 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
|
|
|
4268
4288
|
items,
|
|
4269
4289
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4270
4290
|
};
|
|
4271
|
-
const todosPath =
|
|
4272
|
-
|
|
4291
|
+
const todosPath = path25.join(taskDir, "agent-todos.json");
|
|
4292
|
+
fs23.writeFileSync(todosPath, JSON.stringify(todos, null, 2));
|
|
4273
4293
|
return { success: true, message: `Updated ${items.length} todo items for task '${taskSlug}'.`, count: items.length };
|
|
4274
4294
|
}
|
|
4275
4295
|
var init_sessions = __esm({
|
|
@@ -4389,143 +4409,69 @@ var init_resources3 = __esm({
|
|
|
4389
4409
|
}
|
|
4390
4410
|
});
|
|
4391
4411
|
|
|
4392
|
-
// src/mcp/
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
const basePath = path25.join(getAgentCorePromptsDir(), "_base.md");
|
|
4400
|
-
if (fs23.existsSync(basePath)) {
|
|
4401
|
-
const content = fs23.readFileSync(basePath, "utf-8");
|
|
4402
|
-
baseProtocolCache = content.replace(/^---[\s\S]*?---\n*/, "");
|
|
4403
|
-
return baseProtocolCache;
|
|
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;
|
|
4418
|
+
}
|
|
4404
4419
|
}
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
return prompts.map((p) => {
|
|
4411
|
-
const args = [];
|
|
4412
|
-
if (p.frontmatter["required-args"]) {
|
|
4413
|
-
args.push(...p.frontmatter["required-args"].map((a) => ({
|
|
4414
|
-
name: a.name,
|
|
4415
|
-
description: a.prompt || a.name,
|
|
4416
|
-
required: true
|
|
4417
|
-
})));
|
|
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) }] };
|
|
4418
4425
|
}
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
return {
|
|
4429
|
-
id,
|
|
4430
|
-
name: p.frontmatter.name,
|
|
4431
|
-
description: p.frontmatter.description,
|
|
4432
|
-
arguments: args,
|
|
4433
|
-
content: p.content
|
|
4434
|
-
};
|
|
4435
|
-
});
|
|
4436
|
-
}
|
|
4437
|
-
function getPromptDef(name) {
|
|
4438
|
-
const all = getAllPrompts();
|
|
4439
|
-
const search = name.toLowerCase();
|
|
4440
|
-
return all.find(
|
|
4441
|
-
(p) => p.name === name || p.id === name || p.name.toLowerCase() === search || p.id.toLowerCase() === search
|
|
4442
|
-
);
|
|
4443
|
-
}
|
|
4444
|
-
function renderPromptWithContext(content, args) {
|
|
4445
|
-
const renderArgs = { ...args };
|
|
4446
|
-
let activeProject = detectActiveProject();
|
|
4447
|
-
if (!activeProject) {
|
|
4448
|
-
projectService.refresh();
|
|
4449
|
-
activeProject = detectActiveProject();
|
|
4450
|
-
}
|
|
4451
|
-
const DEFAULT_RRCE_HOME = getEffectiveGlobalPath();
|
|
4452
|
-
let resolvedRrceData = ".rrce-workflow/";
|
|
4453
|
-
let resolvedRrceHome = DEFAULT_RRCE_HOME;
|
|
4454
|
-
let resolvedWorkspaceRoot = process.cwd();
|
|
4455
|
-
let resolvedWorkspaceName = "current-project";
|
|
4456
|
-
if (activeProject) {
|
|
4457
|
-
resolvedRrceData = activeProject.dataPath;
|
|
4458
|
-
if (!resolvedRrceData.endsWith("/") && !resolvedRrceData.endsWith("\\")) {
|
|
4459
|
-
resolvedRrceData += "/";
|
|
4460
|
-
}
|
|
4461
|
-
resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
4462
|
-
resolvedWorkspaceName = activeProject.name;
|
|
4463
|
-
if (activeProject.source === "global") {
|
|
4464
|
-
const workspacesDir = path25.dirname(activeProject.dataPath);
|
|
4465
|
-
resolvedRrceHome = path25.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
|
+
};
|
|
4466
4435
|
}
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
resolvedWorkspaceName = workspaceName;
|
|
4476
|
-
if (!resolvedRrceData.endsWith("/") && !resolvedRrceData.endsWith("\\")) {
|
|
4477
|
-
resolvedRrceData += "/";
|
|
4478
|
-
}
|
|
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 };
|
|
4479
4444
|
}
|
|
4480
|
-
|
|
4445
|
+
return { content: [{ type: "text", text: context }] };
|
|
4481
4446
|
}
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
if (!renderArgs["WORKSPACE_NAME"]) renderArgs["WORKSPACE_NAME"] = resolvedWorkspaceName;
|
|
4487
|
-
const agentContent = renderPrompt(content, renderArgs);
|
|
4488
|
-
const baseProtocol = loadBaseProtocol2();
|
|
4489
|
-
const rendered = baseProtocol ? `${baseProtocol}
|
|
4490
|
-
${agentContent}` : agentContent;
|
|
4491
|
-
return {
|
|
4492
|
-
rendered,
|
|
4493
|
-
context: {
|
|
4494
|
-
RRCE_DATA: resolvedRrceData,
|
|
4495
|
-
RRCE_HOME: resolvedRrceHome,
|
|
4496
|
-
WORKSPACE_ROOT: resolvedWorkspaceRoot,
|
|
4497
|
-
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) }] };
|
|
4498
4451
|
}
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
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;
|
|
4505
4466
|
}
|
|
4506
|
-
return rendered;
|
|
4507
4467
|
}
|
|
4508
|
-
var
|
|
4509
|
-
var
|
|
4510
|
-
"src/mcp/
|
|
4468
|
+
var projectTools;
|
|
4469
|
+
var init_project = __esm({
|
|
4470
|
+
"src/mcp/handlers/tools/project.ts"() {
|
|
4511
4471
|
"use strict";
|
|
4512
|
-
init_prompts();
|
|
4513
4472
|
init_resources2();
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
baseProtocolCache = null;
|
|
4517
|
-
}
|
|
4518
|
-
});
|
|
4519
|
-
|
|
4520
|
-
// src/mcp/handlers/tools.ts
|
|
4521
|
-
import "@modelcontextprotocol/sdk/server/index.js";
|
|
4522
|
-
import {
|
|
4523
|
-
ListToolsRequestSchema,
|
|
4524
|
-
CallToolRequestSchema
|
|
4525
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
4526
|
-
function registerToolHandlers(server) {
|
|
4527
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
4528
|
-
const tools = [
|
|
4473
|
+
init_logger();
|
|
4474
|
+
projectTools = [
|
|
4529
4475
|
{
|
|
4530
4476
|
name: "resolve_path",
|
|
4531
4477
|
description: "Resolve configuration paths (RRCE_DATA, etc.) for a project. Helps determine if a project is using global or local storage.",
|
|
@@ -4537,6 +4483,124 @@ function registerToolHandlers(server) {
|
|
|
4537
4483
|
}
|
|
4538
4484
|
}
|
|
4539
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 = [
|
|
4540
4604
|
{
|
|
4541
4605
|
name: "search_knowledge",
|
|
4542
4606
|
description: "Search across all exposed project knowledge bases. Returns results with token count and optional truncation.",
|
|
@@ -4644,140 +4708,197 @@ function registerToolHandlers(server) {
|
|
|
4644
4708
|
},
|
|
4645
4709
|
required: ["project", "task_slug"]
|
|
4646
4710
|
}
|
|
4647
|
-
}
|
|
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 = [
|
|
4648
4780
|
{
|
|
4649
|
-
name: "
|
|
4650
|
-
description: "
|
|
4781
|
+
name: "list_tasks",
|
|
4782
|
+
description: "List all tasks for a project",
|
|
4651
4783
|
inputSchema: {
|
|
4652
4784
|
type: "object",
|
|
4653
|
-
properties: {
|
|
4654
|
-
project: { type: "string", description: "Name of the project" },
|
|
4655
|
-
keyword: { type: "string", description: "Search in title/summary" },
|
|
4656
|
-
status: { type: "string", description: "Filter by status (draft, in_progress, complete, etc.)" },
|
|
4657
|
-
agent: { type: "string", description: "Filter by agent phase (research, planning, executor, documentation)" },
|
|
4658
|
-
since: { type: "string", description: "ISO date - tasks updated after this date" },
|
|
4659
|
-
limit: { type: "number", description: "Max results (default: 20)" }
|
|
4660
|
-
},
|
|
4785
|
+
properties: { project: { type: "string", description: "Name of the project" } },
|
|
4661
4786
|
required: ["project"]
|
|
4662
4787
|
}
|
|
4663
4788
|
},
|
|
4664
4789
|
{
|
|
4665
|
-
name: "
|
|
4666
|
-
description: "
|
|
4790
|
+
name: "get_task",
|
|
4791
|
+
description: "Get details of a specific task",
|
|
4667
4792
|
inputSchema: {
|
|
4668
4793
|
type: "object",
|
|
4669
4794
|
properties: {
|
|
4670
4795
|
project: { type: "string", description: "Name of the project" },
|
|
4671
|
-
task_slug: { type: "string", description: "The task
|
|
4672
|
-
phase: { type: "string", enum: ["research", "planning", "execution", "documentation"], description: "Phase to validate" }
|
|
4796
|
+
task_slug: { type: "string", description: "The slug of the task" }
|
|
4673
4797
|
},
|
|
4674
|
-
required: ["project", "task_slug"
|
|
4798
|
+
required: ["project", "task_slug"]
|
|
4675
4799
|
}
|
|
4676
4800
|
},
|
|
4677
4801
|
{
|
|
4678
|
-
name: "
|
|
4679
|
-
description: "
|
|
4802
|
+
name: "create_task",
|
|
4803
|
+
description: "Create a new task in the project",
|
|
4680
4804
|
inputSchema: {
|
|
4681
4805
|
type: "object",
|
|
4682
4806
|
properties: {
|
|
4683
|
-
project: { type: "string", description: "Name of the project
|
|
4684
|
-
|
|
4685
|
-
|
|
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" }
|
|
4686
4811
|
},
|
|
4687
|
-
required: ["project"]
|
|
4812
|
+
required: ["project", "task_slug"]
|
|
4688
4813
|
}
|
|
4689
4814
|
},
|
|
4690
4815
|
{
|
|
4691
|
-
name: "
|
|
4692
|
-
description: "
|
|
4693
|
-
inputSchema: { type: "object", properties: {} }
|
|
4694
|
-
},
|
|
4695
|
-
{
|
|
4696
|
-
name: "get_project_context",
|
|
4697
|
-
description: "Get the project context/architecture for a specific project",
|
|
4816
|
+
name: "update_task",
|
|
4817
|
+
description: "Update an existing task",
|
|
4698
4818
|
inputSchema: {
|
|
4699
4819
|
type: "object",
|
|
4700
|
-
properties: {
|
|
4701
|
-
|
|
4820
|
+
properties: {
|
|
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 }
|
|
4824
|
+
},
|
|
4825
|
+
required: ["project", "task_slug", "updates"]
|
|
4702
4826
|
}
|
|
4703
4827
|
},
|
|
4704
4828
|
{
|
|
4705
|
-
name: "
|
|
4706
|
-
description: "
|
|
4707
|
-
inputSchema: { type: "object", properties: {} }
|
|
4708
|
-
},
|
|
4709
|
-
{
|
|
4710
|
-
name: "get_agent_prompt",
|
|
4711
|
-
description: 'Get the system prompt for a specific agent. Accepts agent Name (e.g. "RRCE Init") or ID (e.g. "init").',
|
|
4712
|
-
inputSchema: {
|
|
4713
|
-
type: "object",
|
|
4714
|
-
properties: {
|
|
4715
|
-
agent: { type: "string", description: "Name of the agent (e.g. init, plan, execute)" },
|
|
4716
|
-
args: { type: "object", description: "Arguments for the agent prompt", additionalProperties: true }
|
|
4717
|
-
},
|
|
4718
|
-
required: ["agent"]
|
|
4719
|
-
}
|
|
4720
|
-
},
|
|
4721
|
-
{
|
|
4722
|
-
name: "list_tasks",
|
|
4723
|
-
description: "List all tasks for a project",
|
|
4724
|
-
inputSchema: {
|
|
4725
|
-
type: "object",
|
|
4726
|
-
properties: { project: { type: "string", description: "Name of the project" } },
|
|
4727
|
-
required: ["project"]
|
|
4728
|
-
}
|
|
4729
|
-
},
|
|
4730
|
-
{
|
|
4731
|
-
name: "get_task",
|
|
4732
|
-
description: "Get details of a specific task",
|
|
4733
|
-
inputSchema: {
|
|
4734
|
-
type: "object",
|
|
4735
|
-
properties: {
|
|
4736
|
-
project: { type: "string", description: "Name of the project" },
|
|
4737
|
-
task_slug: { type: "string", description: "The slug of the task" }
|
|
4738
|
-
},
|
|
4739
|
-
required: ["project", "task_slug"]
|
|
4740
|
-
}
|
|
4741
|
-
},
|
|
4742
|
-
{
|
|
4743
|
-
name: "create_task",
|
|
4744
|
-
description: "Create a new task in the project",
|
|
4829
|
+
name: "delete_task",
|
|
4830
|
+
description: "Delete a task from the project",
|
|
4745
4831
|
inputSchema: {
|
|
4746
4832
|
type: "object",
|
|
4747
4833
|
properties: {
|
|
4748
4834
|
project: { type: "string", description: "Name of the project" },
|
|
4749
|
-
task_slug: { type: "string", description: "The slug
|
|
4750
|
-
title: { type: "string", description: "The title of the task" },
|
|
4751
|
-
summary: { type: "string", description: "Brief summary of the task" }
|
|
4835
|
+
task_slug: { type: "string", description: "The slug of the task to delete" }
|
|
4752
4836
|
},
|
|
4753
4837
|
required: ["project", "task_slug"]
|
|
4754
4838
|
}
|
|
4755
4839
|
},
|
|
4756
4840
|
{
|
|
4757
|
-
name: "
|
|
4758
|
-
description: "
|
|
4841
|
+
name: "search_tasks",
|
|
4842
|
+
description: "Search across all tasks by keyword, status, agent phase, or date. Returns matching tasks sorted by relevance.",
|
|
4759
4843
|
inputSchema: {
|
|
4760
4844
|
type: "object",
|
|
4761
4845
|
properties: {
|
|
4762
4846
|
project: { type: "string", description: "Name of the project" },
|
|
4763
|
-
|
|
4764
|
-
|
|
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)" }
|
|
4765
4852
|
},
|
|
4766
|
-
required: ["project"
|
|
4853
|
+
required: ["project"]
|
|
4767
4854
|
}
|
|
4768
4855
|
},
|
|
4769
4856
|
{
|
|
4770
|
-
name: "
|
|
4771
|
-
description: "
|
|
4857
|
+
name: "validate_phase",
|
|
4858
|
+
description: "Check if a task phase has all prerequisites complete. Returns validation result with missing items and suggestions.",
|
|
4772
4859
|
inputSchema: {
|
|
4773
4860
|
type: "object",
|
|
4774
4861
|
properties: {
|
|
4775
4862
|
project: { type: "string", description: "Name of the project" },
|
|
4776
|
-
task_slug: { type: "string", description: "The
|
|
4863
|
+
task_slug: { type: "string", description: "The task slug" },
|
|
4864
|
+
phase: { type: "string", enum: ["research", "planning", "execution", "documentation"], description: "Phase to validate" }
|
|
4777
4865
|
},
|
|
4778
|
-
required: ["project", "task_slug"]
|
|
4866
|
+
required: ["project", "task_slug", "phase"]
|
|
4779
4867
|
}
|
|
4780
|
-
}
|
|
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 = [
|
|
4781
4902
|
{
|
|
4782
4903
|
name: "start_session",
|
|
4783
4904
|
description: "Start an agent session for active task tracking. Call this when beginning work on a task phase.",
|
|
@@ -4833,6 +4954,219 @@ function registerToolHandlers(server) {
|
|
|
4833
4954
|
}
|
|
4834
4955
|
}
|
|
4835
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 += "/";
|
|
5046
|
+
}
|
|
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 = [
|
|
5134
|
+
{
|
|
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: {} }
|
|
5138
|
+
},
|
|
5139
|
+
{
|
|
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").',
|
|
5142
|
+
inputSchema: {
|
|
5143
|
+
type: "object",
|
|
5144
|
+
properties: {
|
|
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 }
|
|
5147
|
+
},
|
|
5148
|
+
required: ["agent"]
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
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
|
+
];
|
|
4836
5170
|
const projects = getExposedProjects();
|
|
4837
5171
|
if (projects.length === 0) {
|
|
4838
5172
|
tools.push({
|
|
@@ -4847,221 +5181,17 @@ function registerToolHandlers(server) {
|
|
|
4847
5181
|
const { name, arguments: args } = request.params;
|
|
4848
5182
|
logger.info(`Calling tool: ${name}`, args);
|
|
4849
5183
|
try {
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
});
|
|
4862
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4863
|
-
}
|
|
4864
|
-
case "search_code": {
|
|
4865
|
-
const params = args;
|
|
4866
|
-
const result = await searchCode(params.query, params.project, params.limit, {
|
|
4867
|
-
max_tokens: params.max_tokens,
|
|
4868
|
-
min_score: params.min_score
|
|
4869
|
-
});
|
|
4870
|
-
if (result.results.length === 0) {
|
|
4871
|
-
return {
|
|
4872
|
-
content: [{
|
|
4873
|
-
type: "text",
|
|
4874
|
-
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."
|
|
4875
|
-
}]
|
|
4876
|
-
};
|
|
4877
|
-
}
|
|
4878
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4879
|
-
}
|
|
4880
|
-
case "find_related_files": {
|
|
4881
|
-
const params = args;
|
|
4882
|
-
const result = await findRelatedFiles2(params.file, params.project, {
|
|
4883
|
-
includeImports: params.include_imports,
|
|
4884
|
-
includeImportedBy: params.include_imported_by,
|
|
4885
|
-
depth: params.depth
|
|
4886
|
-
});
|
|
4887
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4888
|
-
}
|
|
4889
|
-
case "search_symbols": {
|
|
4890
|
-
const params = args;
|
|
4891
|
-
const result = await searchSymbols2(params.name, params.project, {
|
|
4892
|
-
type: params.type,
|
|
4893
|
-
fuzzy: params.fuzzy,
|
|
4894
|
-
limit: params.limit
|
|
4895
|
-
});
|
|
4896
|
-
if (!result.success) {
|
|
4897
|
-
return { content: [{ type: "text", text: result.message || "Search failed" }], isError: true };
|
|
4898
|
-
}
|
|
4899
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4900
|
-
}
|
|
4901
|
-
case "get_file_summary": {
|
|
4902
|
-
const params = args;
|
|
4903
|
-
const result = await getFileSummary(params.file, params.project);
|
|
4904
|
-
if (!result.success) {
|
|
4905
|
-
return { content: [{ type: "text", text: result.message || "Failed to get file summary" }], isError: true };
|
|
4906
|
-
}
|
|
4907
|
-
return { content: [{ type: "text", text: JSON.stringify(result.summary, null, 2) }] };
|
|
4908
|
-
}
|
|
4909
|
-
case "get_context_bundle": {
|
|
4910
|
-
const params = args;
|
|
4911
|
-
const result = await getContextBundle(params.query, params.project, {
|
|
4912
|
-
task_slug: params.task_slug,
|
|
4913
|
-
max_tokens: params.max_tokens,
|
|
4914
|
-
include: params.include
|
|
4915
|
-
});
|
|
4916
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4917
|
-
}
|
|
4918
|
-
case "index_knowledge": {
|
|
4919
|
-
const params = args;
|
|
4920
|
-
const result = await indexKnowledge(params.project, params.force, params.clean);
|
|
4921
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4922
|
-
}
|
|
4923
|
-
case "list_projects": {
|
|
4924
|
-
const projects = getExposedProjects();
|
|
4925
|
-
const list = projects.map((p) => ({ name: p.name, source: p.source, path: p.path }));
|
|
4926
|
-
return {
|
|
4927
|
-
content: [{
|
|
4928
|
-
type: "text",
|
|
4929
|
-
text: JSON.stringify(list, null, 2) + "\n\nTip: Use these project names for tools like `get_project_context` or `index_knowledge`."
|
|
4930
|
-
}]
|
|
4931
|
-
};
|
|
4932
|
-
}
|
|
4933
|
-
case "get_project_context": {
|
|
4934
|
-
const context = getProjectContext(args.project);
|
|
4935
|
-
if (!context) {
|
|
4936
|
-
const projects = getExposedProjects().map((p) => p.name).join(", ");
|
|
4937
|
-
const msg = `No project context found for "${args.project}".
|
|
4938
|
-
Available projects: ${projects}`;
|
|
4939
|
-
logger.warn(msg);
|
|
4940
|
-
return { content: [{ type: "text", text: msg }], isError: true };
|
|
4941
|
-
}
|
|
4942
|
-
return { content: [{ type: "text", text: context }] };
|
|
4943
|
-
}
|
|
4944
|
-
case "list_agents": {
|
|
4945
|
-
const prompts = getAllPrompts();
|
|
4946
|
-
return {
|
|
4947
|
-
content: [{
|
|
4948
|
-
type: "text",
|
|
4949
|
-
text: JSON.stringify(prompts.map((p) => ({
|
|
4950
|
-
name: p.name,
|
|
4951
|
-
id: p.id,
|
|
4952
|
-
description: p.description,
|
|
4953
|
-
arguments: p.arguments
|
|
4954
|
-
})), null, 2) + "\n\nTip: Retrieve the prompt for an agent using `get_agent_prompt` with its name or ID."
|
|
4955
|
-
}]
|
|
4956
|
-
};
|
|
4957
|
-
}
|
|
4958
|
-
case "get_agent_prompt": {
|
|
4959
|
-
const params = args;
|
|
4960
|
-
const agentName = params.agent;
|
|
4961
|
-
const promptDef = getPromptDef(agentName);
|
|
4962
|
-
if (!promptDef) {
|
|
4963
|
-
const available = getAllPrompts().map((p) => `${p.name} (id: ${p.id})`).join(", ");
|
|
4964
|
-
throw new Error(`Agent not found: ${agentName}. Available agents: ${available}`);
|
|
4965
|
-
}
|
|
4966
|
-
const renderArgs = params.args || {};
|
|
4967
|
-
const stringArgs = {};
|
|
4968
|
-
for (const [key, val] of Object.entries(renderArgs)) {
|
|
4969
|
-
stringArgs[key] = String(val);
|
|
4970
|
-
}
|
|
4971
|
-
const { rendered } = renderPromptWithContext(promptDef.content, stringArgs);
|
|
4972
|
-
const contextPreamble = getContextPreamble();
|
|
4973
|
-
return { content: [{ type: "text", text: contextPreamble + rendered }] };
|
|
4974
|
-
}
|
|
4975
|
-
case "list_tasks": {
|
|
4976
|
-
const params = args;
|
|
4977
|
-
const tasks = getProjectTasks(params.project);
|
|
4978
|
-
return { content: [{ type: "text", text: JSON.stringify(tasks, null, 2) }] };
|
|
4979
|
-
}
|
|
4980
|
-
case "get_task": {
|
|
4981
|
-
const params = args;
|
|
4982
|
-
const task = getTask(params.project, params.task_slug);
|
|
4983
|
-
if (!task) {
|
|
4984
|
-
return { content: [{ type: "text", text: `Task '${params.task_slug}' not found in project '${params.project}'.` }], isError: true };
|
|
4985
|
-
}
|
|
4986
|
-
return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
|
|
4987
|
-
}
|
|
4988
|
-
case "create_task": {
|
|
4989
|
-
const params = args;
|
|
4990
|
-
const taskData = {
|
|
4991
|
-
title: params.title || params.task_slug,
|
|
4992
|
-
summary: params.summary || ""
|
|
4993
|
-
};
|
|
4994
|
-
const task = await createTask(params.project, params.task_slug, taskData);
|
|
4995
|
-
return { content: [{ type: "text", text: `\u2713 Task '${params.task_slug}' created. meta.json saved.
|
|
4996
|
-
${JSON.stringify(task, null, 2)}` }] };
|
|
4997
|
-
}
|
|
4998
|
-
case "update_task": {
|
|
4999
|
-
const params = args;
|
|
5000
|
-
const task = await updateTask(params.project, params.task_slug, params.updates);
|
|
5001
|
-
return { content: [{ type: "text", text: `\u2713 Task '${params.task_slug}' updated. meta.json saved.
|
|
5002
|
-
${JSON.stringify(task, null, 2)}` }] };
|
|
5003
|
-
}
|
|
5004
|
-
case "delete_task": {
|
|
5005
|
-
const params = args;
|
|
5006
|
-
const success = deleteTask(params.project, params.task_slug);
|
|
5007
|
-
return { content: [{ type: "text", text: success ? `\u2713 Task '${params.task_slug}' deleted.` : `\u2717 Failed to delete '${params.task_slug}'.` }] };
|
|
5008
|
-
}
|
|
5009
|
-
case "start_session": {
|
|
5010
|
-
const params = args;
|
|
5011
|
-
const result = startSession(params.project, params.task_slug, params.agent, params.phase);
|
|
5012
|
-
return { content: [{ type: "text", text: result.message }], isError: !result.success };
|
|
5013
|
-
}
|
|
5014
|
-
case "end_session": {
|
|
5015
|
-
const params = args;
|
|
5016
|
-
const result = endSession(params.project, params.task_slug);
|
|
5017
|
-
return { content: [{ type: "text", text: result.message }], isError: !result.success };
|
|
5018
|
-
}
|
|
5019
|
-
case "update_agent_todos": {
|
|
5020
|
-
const params = args;
|
|
5021
|
-
const result = updateAgentTodos(params.project, params.task_slug, params.phase, params.agent, params.items);
|
|
5022
|
-
return { content: [{ type: "text", text: result.message }], isError: !result.success };
|
|
5023
|
-
}
|
|
5024
|
-
case "prefetch_task_context": {
|
|
5025
|
-
const params = args;
|
|
5026
|
-
const result = await prefetchTaskContext(params.project, params.task_slug, {
|
|
5027
|
-
max_tokens: params.max_tokens
|
|
5028
|
-
});
|
|
5029
|
-
if (!result.success) {
|
|
5030
|
-
return { content: [{ type: "text", text: result.message || "Failed to prefetch task context" }], isError: true };
|
|
5031
|
-
}
|
|
5032
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5033
|
-
}
|
|
5034
|
-
case "search_tasks": {
|
|
5035
|
-
const params = args;
|
|
5036
|
-
const results = searchTasks(params.project, {
|
|
5037
|
-
keyword: params.keyword,
|
|
5038
|
-
status: params.status,
|
|
5039
|
-
agent: params.agent,
|
|
5040
|
-
since: params.since,
|
|
5041
|
-
limit: params.limit
|
|
5042
|
-
});
|
|
5043
|
-
return { content: [{ type: "text", text: JSON.stringify({ count: results.length, tasks: results }, null, 2) }] };
|
|
5044
|
-
}
|
|
5045
|
-
case "validate_phase": {
|
|
5046
|
-
const params = args;
|
|
5047
|
-
const result = validatePhase(params.project, params.task_slug, params.phase);
|
|
5048
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5049
|
-
}
|
|
5050
|
-
case "help_setup": {
|
|
5051
|
-
const msg = `
|
|
5052
|
-
RRCE MCP Server is running, but no projects are configured/exposed.
|
|
5053
|
-
|
|
5054
|
-
To fix this:
|
|
5055
|
-
1. Open a terminal.
|
|
5056
|
-
2. Run: npx rrce-workflow mcp configure
|
|
5057
|
-
3. Select the projects you want to expose to the AI.
|
|
5058
|
-
4. Restart the MCP server (or it may pick up changes automatically).
|
|
5059
|
-
`;
|
|
5060
|
-
return { content: [{ type: "text", text: msg }] };
|
|
5061
|
-
}
|
|
5062
|
-
default:
|
|
5063
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
5064
|
-
}
|
|
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}`);
|
|
5065
5195
|
} catch (error) {
|
|
5066
5196
|
logger.error(`Tool execution failed: ${name}`, error);
|
|
5067
5197
|
throw error;
|
|
@@ -5073,7 +5203,11 @@ var init_tools = __esm({
|
|
|
5073
5203
|
"use strict";
|
|
5074
5204
|
init_logger();
|
|
5075
5205
|
init_resources2();
|
|
5076
|
-
|
|
5206
|
+
init_project();
|
|
5207
|
+
init_search2();
|
|
5208
|
+
init_task();
|
|
5209
|
+
init_session();
|
|
5210
|
+
init_agent();
|
|
5077
5211
|
}
|
|
5078
5212
|
});
|
|
5079
5213
|
|
|
@@ -5299,8 +5433,8 @@ Hidden projects: ${projects.length - exposedCount}`,
|
|
|
5299
5433
|
}
|
|
5300
5434
|
async function handleConfigureGlobalPath() {
|
|
5301
5435
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
5302
|
-
const
|
|
5303
|
-
const
|
|
5436
|
+
const fs34 = await import("fs");
|
|
5437
|
+
const path33 = await import("path");
|
|
5304
5438
|
note3(
|
|
5305
5439
|
`MCP Hub requires a ${pc5.bold("global storage path")} to store its configuration
|
|
5306
5440
|
and coordinate across projects.
|
|
@@ -5314,8 +5448,8 @@ locally in each project. MCP needs a central location.`,
|
|
|
5314
5448
|
return false;
|
|
5315
5449
|
}
|
|
5316
5450
|
try {
|
|
5317
|
-
if (!
|
|
5318
|
-
|
|
5451
|
+
if (!fs34.existsSync(resolvedPath)) {
|
|
5452
|
+
fs34.mkdirSync(resolvedPath, { recursive: true });
|
|
5319
5453
|
}
|
|
5320
5454
|
const config = loadMCPConfig();
|
|
5321
5455
|
saveMCPConfig(config);
|
|
@@ -5323,7 +5457,7 @@ locally in each project. MCP needs a central location.`,
|
|
|
5323
5457
|
`${pc5.green("\u2713")} Global path configured: ${pc5.cyan(resolvedPath)}
|
|
5324
5458
|
|
|
5325
5459
|
MCP config will be stored at:
|
|
5326
|
-
${
|
|
5460
|
+
${path33.join(resolvedPath, "mcp.yaml")}`,
|
|
5327
5461
|
"Configuration Saved"
|
|
5328
5462
|
);
|
|
5329
5463
|
return true;
|
|
@@ -5427,15 +5561,15 @@ __export(ConfigContext_exports, {
|
|
|
5427
5561
|
useConfig: () => useConfig
|
|
5428
5562
|
});
|
|
5429
5563
|
import { createContext, useContext, useState, useCallback, useMemo, useEffect } from "react";
|
|
5430
|
-
import * as
|
|
5431
|
-
import * as
|
|
5564
|
+
import * as fs25 from "fs";
|
|
5565
|
+
import * as path27 from "path";
|
|
5432
5566
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
5433
5567
|
function getPackageVersion() {
|
|
5434
5568
|
try {
|
|
5435
5569
|
const agentCoreDir = getAgentCoreDir();
|
|
5436
|
-
const packageJsonPath =
|
|
5437
|
-
if (
|
|
5438
|
-
return JSON.parse(
|
|
5570
|
+
const packageJsonPath = path27.join(path27.dirname(agentCoreDir), "package.json");
|
|
5571
|
+
if (fs25.existsSync(packageJsonPath)) {
|
|
5572
|
+
return JSON.parse(fs25.readFileSync(packageJsonPath, "utf8")).version;
|
|
5439
5573
|
}
|
|
5440
5574
|
} catch (e) {
|
|
5441
5575
|
}
|
|
@@ -5502,16 +5636,16 @@ var init_ConfigContext = __esm({
|
|
|
5502
5636
|
});
|
|
5503
5637
|
|
|
5504
5638
|
// src/mcp/ui/lib/tasks-fs.ts
|
|
5505
|
-
import * as
|
|
5506
|
-
import * as
|
|
5639
|
+
import * as fs26 from "fs";
|
|
5640
|
+
import * as path28 from "path";
|
|
5507
5641
|
function readSession(project, taskSlug) {
|
|
5508
5642
|
const rrceData = getProjectRRCEData(project);
|
|
5509
|
-
const sessionPath =
|
|
5510
|
-
if (!
|
|
5643
|
+
const sessionPath = path28.join(rrceData, "tasks", taskSlug, "session.json");
|
|
5644
|
+
if (!fs26.existsSync(sessionPath)) {
|
|
5511
5645
|
return null;
|
|
5512
5646
|
}
|
|
5513
5647
|
try {
|
|
5514
|
-
const raw =
|
|
5648
|
+
const raw = fs26.readFileSync(sessionPath, "utf-8");
|
|
5515
5649
|
return JSON.parse(raw);
|
|
5516
5650
|
} catch {
|
|
5517
5651
|
return null;
|
|
@@ -5524,12 +5658,12 @@ function isSessionStale(session, thresholdMs = SESSION_STALE_THRESHOLD_MS) {
|
|
|
5524
5658
|
}
|
|
5525
5659
|
function readAgentTodos(project, taskSlug) {
|
|
5526
5660
|
const rrceData = getProjectRRCEData(project);
|
|
5527
|
-
const todosPath =
|
|
5528
|
-
if (!
|
|
5661
|
+
const todosPath = path28.join(rrceData, "tasks", taskSlug, "agent-todos.json");
|
|
5662
|
+
if (!fs26.existsSync(todosPath)) {
|
|
5529
5663
|
return null;
|
|
5530
5664
|
}
|
|
5531
5665
|
try {
|
|
5532
|
-
const raw =
|
|
5666
|
+
const raw = fs26.readFileSync(todosPath, "utf-8");
|
|
5533
5667
|
return JSON.parse(raw);
|
|
5534
5668
|
} catch {
|
|
5535
5669
|
return null;
|
|
@@ -5542,8 +5676,8 @@ function detectStorageModeFromConfig(workspaceRoot) {
|
|
|
5542
5676
|
if (configPath.startsWith(rrceHome)) {
|
|
5543
5677
|
return "global";
|
|
5544
5678
|
}
|
|
5545
|
-
if (
|
|
5546
|
-
const content =
|
|
5679
|
+
if (fs26.existsSync(configPath)) {
|
|
5680
|
+
const content = fs26.readFileSync(configPath, "utf-8");
|
|
5547
5681
|
if (content.includes("mode: workspace")) return "workspace";
|
|
5548
5682
|
if (content.includes("mode: global")) return "global";
|
|
5549
5683
|
}
|
|
@@ -5553,7 +5687,7 @@ function detectStorageModeFromConfig(workspaceRoot) {
|
|
|
5553
5687
|
}
|
|
5554
5688
|
function getEffectiveGlobalBase() {
|
|
5555
5689
|
const dummy = resolveDataPath("global", "__rrce_dummy__", "");
|
|
5556
|
-
return
|
|
5690
|
+
return path28.dirname(path28.dirname(dummy));
|
|
5557
5691
|
}
|
|
5558
5692
|
function getProjectRRCEData(project) {
|
|
5559
5693
|
const workspaceRoot = project.sourcePath || project.path;
|
|
@@ -5562,19 +5696,19 @@ function getProjectRRCEData(project) {
|
|
|
5562
5696
|
}
|
|
5563
5697
|
function listProjectTasks(project) {
|
|
5564
5698
|
const rrceData = getProjectRRCEData(project);
|
|
5565
|
-
const tasksPath =
|
|
5566
|
-
if (!
|
|
5699
|
+
const tasksPath = path28.join(rrceData, "tasks");
|
|
5700
|
+
if (!fs26.existsSync(tasksPath)) {
|
|
5567
5701
|
return { projectName: project.name, tasksPath, tasks: [] };
|
|
5568
5702
|
}
|
|
5569
5703
|
const tasks = [];
|
|
5570
5704
|
try {
|
|
5571
|
-
const entries =
|
|
5705
|
+
const entries = fs26.readdirSync(tasksPath, { withFileTypes: true });
|
|
5572
5706
|
for (const entry of entries) {
|
|
5573
5707
|
if (!entry.isDirectory()) continue;
|
|
5574
|
-
const metaPath =
|
|
5575
|
-
if (!
|
|
5708
|
+
const metaPath = path28.join(tasksPath, entry.name, "meta.json");
|
|
5709
|
+
if (!fs26.existsSync(metaPath)) continue;
|
|
5576
5710
|
try {
|
|
5577
|
-
const raw =
|
|
5711
|
+
const raw = fs26.readFileSync(metaPath, "utf-8");
|
|
5578
5712
|
const meta = JSON.parse(raw);
|
|
5579
5713
|
if (!meta.task_slug) meta.task_slug = entry.name;
|
|
5580
5714
|
tasks.push(meta);
|
|
@@ -5593,18 +5727,18 @@ function listProjectTasks(project) {
|
|
|
5593
5727
|
}
|
|
5594
5728
|
function updateTaskStatus(project, taskSlug, status) {
|
|
5595
5729
|
const rrceData = getProjectRRCEData(project);
|
|
5596
|
-
const metaPath =
|
|
5597
|
-
if (!
|
|
5730
|
+
const metaPath = path28.join(rrceData, "tasks", taskSlug, "meta.json");
|
|
5731
|
+
if (!fs26.existsSync(metaPath)) {
|
|
5598
5732
|
return { ok: false, error: `meta.json not found for task '${taskSlug}'` };
|
|
5599
5733
|
}
|
|
5600
5734
|
try {
|
|
5601
|
-
const meta = JSON.parse(
|
|
5735
|
+
const meta = JSON.parse(fs26.readFileSync(metaPath, "utf-8"));
|
|
5602
5736
|
const next = {
|
|
5603
5737
|
...meta,
|
|
5604
5738
|
status,
|
|
5605
5739
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5606
5740
|
};
|
|
5607
|
-
|
|
5741
|
+
fs26.writeFileSync(metaPath, JSON.stringify(next, null, 2));
|
|
5608
5742
|
return { ok: true, meta: next };
|
|
5609
5743
|
} catch (e) {
|
|
5610
5744
|
return { ok: false, error: String(e) };
|
|
@@ -5962,31 +6096,54 @@ var init_project_utils = __esm({
|
|
|
5962
6096
|
}
|
|
5963
6097
|
});
|
|
5964
6098
|
|
|
5965
|
-
// src/mcp/ui/
|
|
5966
|
-
import
|
|
5967
|
-
import { Box as Box4, Text as Text4
|
|
5968
|
-
import * as fs26 from "fs";
|
|
5969
|
-
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";
|
|
5970
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";
|
|
5971
6128
|
function getIndexStats(project) {
|
|
5972
6129
|
const stats = { knowledgeCount: 0, codeCount: 0, lastIndexed: null };
|
|
5973
6130
|
try {
|
|
5974
6131
|
const knowledgePath = project.knowledgePath;
|
|
5975
6132
|
if (knowledgePath) {
|
|
5976
|
-
const embPath =
|
|
5977
|
-
const codeEmbPath =
|
|
5978
|
-
if (
|
|
5979
|
-
const stat =
|
|
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);
|
|
5980
6137
|
stats.lastIndexed = stat.mtime.toISOString();
|
|
5981
6138
|
try {
|
|
5982
|
-
const data = JSON.parse(
|
|
6139
|
+
const data = JSON.parse(fs27.readFileSync(embPath, "utf-8"));
|
|
5983
6140
|
stats.knowledgeCount = Array.isArray(data) ? data.length : Object.keys(data).length;
|
|
5984
6141
|
} catch {
|
|
5985
6142
|
}
|
|
5986
6143
|
}
|
|
5987
|
-
if (
|
|
6144
|
+
if (fs27.existsSync(codeEmbPath)) {
|
|
5988
6145
|
try {
|
|
5989
|
-
const data = JSON.parse(
|
|
6146
|
+
const data = JSON.parse(fs27.readFileSync(codeEmbPath, "utf-8"));
|
|
5990
6147
|
stats.codeCount = Array.isArray(data) ? data.length : Object.keys(data).length;
|
|
5991
6148
|
} catch {
|
|
5992
6149
|
}
|
|
@@ -5996,6 +6153,16 @@ function getIndexStats(project) {
|
|
|
5996
6153
|
}
|
|
5997
6154
|
return stats;
|
|
5998
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";
|
|
5999
6166
|
var ProjectsView;
|
|
6000
6167
|
var init_ProjectsView = __esm({
|
|
6001
6168
|
"src/mcp/ui/ProjectsView.tsx"() {
|
|
@@ -6007,6 +6174,8 @@ var init_ProjectsView = __esm({
|
|
|
6007
6174
|
init_config_utils();
|
|
6008
6175
|
init_project_utils();
|
|
6009
6176
|
init_ui_helpers();
|
|
6177
|
+
init_ProjectViews();
|
|
6178
|
+
init_projects2();
|
|
6010
6179
|
ProjectsView = ({ config: initialConfig, projects: allProjects, onConfigChange, workspacePath }) => {
|
|
6011
6180
|
const { driftReports, checkAllDrift } = useConfig();
|
|
6012
6181
|
const [config, setConfig] = useState3(initialConfig);
|
|
@@ -6112,20 +6281,10 @@ ${statsRow}` : label;
|
|
|
6112
6281
|
setConfig(newConfig);
|
|
6113
6282
|
onConfigChange?.();
|
|
6114
6283
|
};
|
|
6115
|
-
return /* @__PURE__ */
|
|
6116
|
-
/* @__PURE__ */
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
/* @__PURE__ */ jsx5(Text4, { color: "dim", children: " \u2502 " }),
|
|
6120
|
-
/* @__PURE__ */ jsxs3(Text4, { color: config.defaults.includeNew ? "green" : "red", children: [
|
|
6121
|
-
"Auto-expose: ",
|
|
6122
|
-
config.defaults.includeNew ? "ON" : "OFF"
|
|
6123
|
-
] })
|
|
6124
|
-
] }),
|
|
6125
|
-
/* @__PURE__ */ jsx5(Text4, { color: "dim", children: "v0.3.14" })
|
|
6126
|
-
] }),
|
|
6127
|
-
/* @__PURE__ */ jsx5(Box4, { marginTop: 1, paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Manage which projects are exposed to the MCP server." }) }),
|
|
6128
|
-
/* @__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(
|
|
6129
6288
|
SimpleSelect,
|
|
6130
6289
|
{
|
|
6131
6290
|
message: "",
|
|
@@ -6140,111 +6299,7 @@ ${statsRow}` : label;
|
|
|
6140
6299
|
},
|
|
6141
6300
|
JSON.stringify(initialSelected) + config.defaults.includeNew + JSON.stringify(indexingStats)
|
|
6142
6301
|
) }),
|
|
6143
|
-
/* @__PURE__ */
|
|
6144
|
-
/* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Space:Select Enter:Save a:Toggle Auto u:Refresh Drift" }),
|
|
6145
|
-
/* @__PURE__ */ jsx5(Text4, { color: "dim", children: "Use 'rrce-workflow wizard' for advanced config" })
|
|
6146
|
-
] })
|
|
6147
|
-
] });
|
|
6148
|
-
};
|
|
6149
|
-
}
|
|
6150
|
-
});
|
|
6151
|
-
|
|
6152
|
-
// src/mcp/ui/components/TaskRow.tsx
|
|
6153
|
-
import "react";
|
|
6154
|
-
import { Box as Box5, Text as Text5 } from "ink";
|
|
6155
|
-
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
6156
|
-
function getActiveAgent(task) {
|
|
6157
|
-
if (!task.agents) return null;
|
|
6158
|
-
for (const [agent, info] of Object.entries(task.agents)) {
|
|
6159
|
-
if (info?.status === "in_progress") {
|
|
6160
|
-
return { agent, status: "in_progress" };
|
|
6161
|
-
}
|
|
6162
|
-
}
|
|
6163
|
-
const agentOrder = ["documentation", "executor", "planning", "research"];
|
|
6164
|
-
for (const agent of agentOrder) {
|
|
6165
|
-
if (task.agents[agent]?.status === "complete") {
|
|
6166
|
-
return { agent, status: "complete" };
|
|
6167
|
-
}
|
|
6168
|
-
}
|
|
6169
|
-
return null;
|
|
6170
|
-
}
|
|
6171
|
-
var TaskRow;
|
|
6172
|
-
var init_TaskRow = __esm({
|
|
6173
|
-
"src/mcp/ui/components/TaskRow.tsx"() {
|
|
6174
|
-
"use strict";
|
|
6175
|
-
init_ui_helpers();
|
|
6176
|
-
init_project_utils();
|
|
6177
|
-
TaskRow = ({
|
|
6178
|
-
row,
|
|
6179
|
-
isSelected,
|
|
6180
|
-
isExpanded,
|
|
6181
|
-
taskCount,
|
|
6182
|
-
hasDrift,
|
|
6183
|
-
isCurrentProject = false,
|
|
6184
|
-
isLastTask = false
|
|
6185
|
-
}) => {
|
|
6186
|
-
if (row.kind === "project") {
|
|
6187
|
-
const projectColor = isSelected ? "cyan" : isCurrentProject ? "yellow" : "white";
|
|
6188
|
-
const isBold = isSelected || isCurrentProject;
|
|
6189
|
-
return /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
6190
|
-
/* @__PURE__ */ jsx6(Text5, { color: isSelected ? "cyan" : "dim", children: isSelected ? "\u25B8 " : " " }),
|
|
6191
|
-
/* @__PURE__ */ jsxs4(Text5, { bold: isBold, color: projectColor, children: [
|
|
6192
|
-
getFolderIcon(isExpanded),
|
|
6193
|
-
" ",
|
|
6194
|
-
formatProjectLabel(row.project)
|
|
6195
|
-
] }),
|
|
6196
|
-
isCurrentProject && /* @__PURE__ */ jsx6(Text5, { color: "yellow", dimColor: true, children: " (current)" }),
|
|
6197
|
-
hasDrift && /* @__PURE__ */ jsx6(Text5, { color: "magenta", children: " \u26A0" }),
|
|
6198
|
-
/* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
|
|
6199
|
-
" ",
|
|
6200
|
-
taskCount > 0 ? `[${taskCount}]` : ""
|
|
6201
|
-
] })
|
|
6202
|
-
] });
|
|
6203
|
-
}
|
|
6204
|
-
const task = row.task;
|
|
6205
|
-
const taskLabel = task.title || task.task_slug;
|
|
6206
|
-
const status = task.status || "";
|
|
6207
|
-
const isPlaceholder = task.task_slug === "__none__";
|
|
6208
|
-
const branch = getTreeBranch(isLastTask);
|
|
6209
|
-
const activeAgent = getActiveAgent(task);
|
|
6210
|
-
const progress = getChecklistProgress(task.checklist || []);
|
|
6211
|
-
const relativeTime = task.updated_at ? formatRelativeTime(task.updated_at) : "";
|
|
6212
|
-
if (isPlaceholder) {
|
|
6213
|
-
return /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
6214
|
-
/* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
|
|
6215
|
-
" ",
|
|
6216
|
-
branch,
|
|
6217
|
-
" "
|
|
6218
|
-
] }),
|
|
6219
|
-
/* @__PURE__ */ jsx6(Text5, { color: "dim", italic: true, children: taskLabel })
|
|
6220
|
-
] });
|
|
6221
|
-
}
|
|
6222
|
-
return /* @__PURE__ */ jsxs4(Box5, { children: [
|
|
6223
|
-
/* @__PURE__ */ jsx6(Text5, { color: isSelected ? "cyan" : "dim", children: isSelected ? "\u25B8 " : " " }),
|
|
6224
|
-
/* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
|
|
6225
|
-
branch,
|
|
6226
|
-
" "
|
|
6227
|
-
] }),
|
|
6228
|
-
/* @__PURE__ */ jsx6(Text5, { color: isSelected ? "cyan" : "white", children: "\u{1F4CB} " }),
|
|
6229
|
-
/* @__PURE__ */ jsx6(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx6(Text5, { bold: isSelected, color: isSelected ? "cyan" : "white", children: taskLabel.length > 25 ? taskLabel.substring(0, 22) + "..." : taskLabel }) }),
|
|
6230
|
-
activeAgent && /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
6231
|
-
/* @__PURE__ */ jsx6(Text5, { color: "dim", children: " " }),
|
|
6232
|
-
/* @__PURE__ */ jsx6(Text5, { children: getPhaseIcon(activeAgent.agent) }),
|
|
6233
|
-
/* @__PURE__ */ jsx6(Text5, { color: activeAgent.status === "in_progress" ? "yellow" : "green", children: getAgentStatusIcon(activeAgent.status) })
|
|
6234
|
-
] }),
|
|
6235
|
-
progress.total > 0 && /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
|
|
6236
|
-
" ",
|
|
6237
|
-
getProgressBar(progress.percentage, 6),
|
|
6238
|
-
" ",
|
|
6239
|
-
progress.completed,
|
|
6240
|
-
"/",
|
|
6241
|
-
progress.total
|
|
6242
|
-
] }),
|
|
6243
|
-
relativeTime && relativeTime !== "\u2014" && /* @__PURE__ */ jsxs4(Text5, { color: "dim", children: [
|
|
6244
|
-
" ",
|
|
6245
|
-
relativeTime
|
|
6246
|
-
] }),
|
|
6247
|
-
!activeAgent && status && /* @__PURE__ */ jsx6(Text5, { color: getStatusColor(status), children: ` ${getStatusIcon(status)} ${status}` })
|
|
6302
|
+
/* @__PURE__ */ jsx6(ProjectsFooter, {})
|
|
6248
6303
|
] });
|
|
6249
6304
|
};
|
|
6250
6305
|
}
|
|
@@ -6374,10 +6429,184 @@ var init_TaskDetails = __esm({
|
|
|
6374
6429
|
}
|
|
6375
6430
|
});
|
|
6376
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
|
+
|
|
6377
6606
|
// src/mcp/ui/TasksView.tsx
|
|
6378
6607
|
import { useEffect as useEffect4, useMemo as useMemo4, useState as useState4 } from "react";
|
|
6379
|
-
import { Box as
|
|
6380
|
-
import { jsx as
|
|
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";
|
|
6381
6610
|
function nextStatus(current) {
|
|
6382
6611
|
const idx = STATUS_CYCLE.indexOf(current || "");
|
|
6383
6612
|
if (idx === -1) return STATUS_CYCLE[0];
|
|
@@ -6390,8 +6619,9 @@ var init_TasksView = __esm({
|
|
|
6390
6619
|
init_tasks_fs();
|
|
6391
6620
|
init_ConfigContext();
|
|
6392
6621
|
init_project_utils();
|
|
6393
|
-
init_TaskRow();
|
|
6394
6622
|
init_TaskDetails();
|
|
6623
|
+
init_TaskTree();
|
|
6624
|
+
init_TaskViews();
|
|
6395
6625
|
STATUS_CYCLE = ["pending", "in_progress", "blocked", "complete"];
|
|
6396
6626
|
TasksView = ({ projects: allProjects, workspacePath }) => {
|
|
6397
6627
|
const { driftReports } = useConfig();
|
|
@@ -6512,55 +6742,26 @@ var init_TasksView = __esm({
|
|
|
6512
6742
|
const selectedRow = flattenedRows[selectedIndex];
|
|
6513
6743
|
const selectedTask = selectedRow?.kind === "task" && selectedRow.task.task_slug !== "__none__" ? selectedRow.task : null;
|
|
6514
6744
|
const totalTasks = Object.values(taskCache).flat().length;
|
|
6515
|
-
return /* @__PURE__ */
|
|
6516
|
-
/* @__PURE__ */
|
|
6517
|
-
|
|
6518
|
-
/* @__PURE__ */ jsx8(Text7, { bold: true, color: "cyan", children: "\u2699 Tasks" }),
|
|
6519
|
-
/* @__PURE__ */ jsx8(Text7, { color: "dim", children: " \u2502 " }),
|
|
6520
|
-
/* @__PURE__ */ jsxs6(Text7, { children: [
|
|
6521
|
-
sortedProjects.length,
|
|
6522
|
-
" projects"
|
|
6523
|
-
] }),
|
|
6524
|
-
/* @__PURE__ */ jsx8(Text7, { color: "dim", children: " \u2022 " }),
|
|
6525
|
-
/* @__PURE__ */ jsxs6(Text7, { children: [
|
|
6526
|
-
totalTasks,
|
|
6527
|
-
" tasks"
|
|
6528
|
-
] })
|
|
6529
|
-
] }),
|
|
6530
|
-
/* @__PURE__ */ jsx8(Text7, { color: "dim", children: "v0.3.14" })
|
|
6531
|
-
] }),
|
|
6532
|
-
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: [
|
|
6533
6748
|
"\u26A0 ",
|
|
6534
6749
|
errorLine
|
|
6535
6750
|
] }) }),
|
|
6536
|
-
/* @__PURE__ */
|
|
6537
|
-
/* @__PURE__ */
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
isSelected: idx === selectedIndex,
|
|
6549
|
-
isExpanded: expanded.has(k),
|
|
6550
|
-
taskCount: (taskCache[k] || []).length,
|
|
6551
|
-
hasDrift: !!driftReports[row.project.path]?.hasDrift,
|
|
6552
|
-
isCurrentProject,
|
|
6553
|
-
isLastTask
|
|
6554
|
-
},
|
|
6555
|
-
row.kind === "project" ? `p:${k}` : `t:${k}:${row.task.task_slug}`
|
|
6556
|
-
);
|
|
6557
|
-
}) }) }),
|
|
6558
|
-
/* @__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 }) })
|
|
6559
6763
|
] }),
|
|
6560
|
-
/* @__PURE__ */
|
|
6561
|
-
/* @__PURE__ */ jsx8(Text7, { color: "dim", children: "\u2191\u2193:Nav Enter:Expand s:Cycle Status R:Refresh" }),
|
|
6562
|
-
/* @__PURE__ */ jsx8(Text7, { color: "dim", children: "Press 'q' to exit" })
|
|
6563
|
-
] })
|
|
6764
|
+
/* @__PURE__ */ jsx11(TasksFooter, {})
|
|
6564
6765
|
] });
|
|
6565
6766
|
};
|
|
6566
6767
|
}
|
|
@@ -6568,8 +6769,8 @@ var init_TasksView = __esm({
|
|
|
6568
6769
|
|
|
6569
6770
|
// src/mcp/ui/LogViewer.tsx
|
|
6570
6771
|
import "react";
|
|
6571
|
-
import { Box as
|
|
6572
|
-
import { jsx as
|
|
6772
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
6773
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
6573
6774
|
var LogViewer;
|
|
6574
6775
|
var init_LogViewer = __esm({
|
|
6575
6776
|
"src/mcp/ui/LogViewer.tsx"() {
|
|
@@ -6579,16 +6780,16 @@ var init_LogViewer = __esm({
|
|
|
6579
6780
|
const emptyLines = Math.max(0, height - visibleLogs.length);
|
|
6580
6781
|
const padding = Array(emptyLines).fill("");
|
|
6581
6782
|
const formatLog = (log) => {
|
|
6582
|
-
if (log.includes("[RAG]")) return /* @__PURE__ */
|
|
6583
|
-
if (log.includes("[ERROR]")) return /* @__PURE__ */
|
|
6584
|
-
if (log.includes("[WARN]")) return /* @__PURE__ */
|
|
6585
|
-
if (log.includes("[INFO]")) return /* @__PURE__ */
|
|
6586
|
-
if (log.includes("Success")) return /* @__PURE__ */
|
|
6587
|
-
return /* @__PURE__ */
|
|
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 });
|
|
6588
6789
|
};
|
|
6589
|
-
return /* @__PURE__ */
|
|
6590
|
-
padding.map((_, i) => /* @__PURE__ */
|
|
6591
|
-
visibleLogs.map((log, i) => /* @__PURE__ */
|
|
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}`))
|
|
6592
6793
|
] });
|
|
6593
6794
|
};
|
|
6594
6795
|
}
|
|
@@ -6596,28 +6797,28 @@ var init_LogViewer = __esm({
|
|
|
6596
6797
|
|
|
6597
6798
|
// src/mcp/ui/StatusBoard.tsx
|
|
6598
6799
|
import "react";
|
|
6599
|
-
import { Box as
|
|
6600
|
-
import { jsx as
|
|
6800
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
6801
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
6601
6802
|
var StatusBoard;
|
|
6602
6803
|
var init_StatusBoard = __esm({
|
|
6603
6804
|
"src/mcp/ui/StatusBoard.tsx"() {
|
|
6604
6805
|
"use strict";
|
|
6605
6806
|
StatusBoard = ({ exposedLabel, port, pid, running, hasDrift }) => {
|
|
6606
|
-
return /* @__PURE__ */
|
|
6607
|
-
running ? /* @__PURE__ */
|
|
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" }),
|
|
6608
6809
|
" ",
|
|
6609
6810
|
"\u2502",
|
|
6610
6811
|
" \u{1F4CB} ",
|
|
6611
|
-
/* @__PURE__ */
|
|
6812
|
+
/* @__PURE__ */ jsx13(Text12, { color: "yellow", children: exposedLabel }),
|
|
6612
6813
|
" ",
|
|
6613
6814
|
"\u2502",
|
|
6614
6815
|
" Port: ",
|
|
6615
|
-
/* @__PURE__ */
|
|
6816
|
+
/* @__PURE__ */ jsx13(Text12, { color: "green", children: port }),
|
|
6616
6817
|
" ",
|
|
6617
6818
|
"\u2502",
|
|
6618
6819
|
" PID: ",
|
|
6619
|
-
/* @__PURE__ */
|
|
6620
|
-
hasDrift && /* @__PURE__ */
|
|
6820
|
+
/* @__PURE__ */ jsx13(Text12, { color: "green", children: pid }),
|
|
6821
|
+
hasDrift && /* @__PURE__ */ jsxs11(Text12, { color: "magenta", bold: true, children: [
|
|
6621
6822
|
" ",
|
|
6622
6823
|
"\u2502",
|
|
6623
6824
|
" \u2B06 UPDATE AVAILABLE"
|
|
@@ -6629,8 +6830,8 @@ var init_StatusBoard = __esm({
|
|
|
6629
6830
|
|
|
6630
6831
|
// src/mcp/ui/components/TabBar.tsx
|
|
6631
6832
|
import "react";
|
|
6632
|
-
import { Box as
|
|
6633
|
-
import { jsx as
|
|
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";
|
|
6634
6835
|
var TabBar;
|
|
6635
6836
|
var init_TabBar = __esm({
|
|
6636
6837
|
"src/mcp/ui/components/TabBar.tsx"() {
|
|
@@ -6660,11 +6861,11 @@ var init_TabBar = __esm({
|
|
|
6660
6861
|
if (tab) onChange(tab.id);
|
|
6661
6862
|
}
|
|
6662
6863
|
});
|
|
6663
|
-
return /* @__PURE__ */
|
|
6864
|
+
return /* @__PURE__ */ jsxs12(Box13, { borderStyle: "single", paddingX: 1, borderColor: "gray", children: [
|
|
6664
6865
|
tabs.map((tab, index) => {
|
|
6665
6866
|
const isActive = tab.id === activeTab;
|
|
6666
|
-
return /* @__PURE__ */
|
|
6667
|
-
|
|
6867
|
+
return /* @__PURE__ */ jsx14(Box13, { marginRight: 2, children: /* @__PURE__ */ jsx14(
|
|
6868
|
+
Text13,
|
|
6668
6869
|
{
|
|
6669
6870
|
color: isActive ? "cyan" : "white",
|
|
6670
6871
|
bold: isActive,
|
|
@@ -6673,8 +6874,8 @@ var init_TabBar = __esm({
|
|
|
6673
6874
|
}
|
|
6674
6875
|
) }, tab.id);
|
|
6675
6876
|
}),
|
|
6676
|
-
/* @__PURE__ */
|
|
6677
|
-
/* @__PURE__ */
|
|
6877
|
+
/* @__PURE__ */ jsx14(Box13, { flexGrow: 1 }),
|
|
6878
|
+
/* @__PURE__ */ jsx14(Text13, { color: "dim", children: "Use \u25C4/\u25BA arrows to navigate" })
|
|
6678
6879
|
] });
|
|
6679
6880
|
};
|
|
6680
6881
|
}
|
|
@@ -6686,9 +6887,9 @@ __export(App_exports, {
|
|
|
6686
6887
|
App: () => App
|
|
6687
6888
|
});
|
|
6688
6889
|
import { useState as useState5, useEffect as useEffect6, useMemo as useMemo5, useCallback as useCallback3 } from "react";
|
|
6689
|
-
import { Box as
|
|
6690
|
-
import
|
|
6691
|
-
import { jsx as
|
|
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";
|
|
6692
6893
|
var App;
|
|
6693
6894
|
var init_App = __esm({
|
|
6694
6895
|
"src/mcp/ui/App.tsx"() {
|
|
@@ -6760,18 +6961,18 @@ var init_App = __esm({
|
|
|
6760
6961
|
useEffect6(() => {
|
|
6761
6962
|
const logPath = getLogFilePath();
|
|
6762
6963
|
let lastSize = 0;
|
|
6763
|
-
if (
|
|
6764
|
-
const stats =
|
|
6964
|
+
if (fs28.existsSync(logPath)) {
|
|
6965
|
+
const stats = fs28.statSync(logPath);
|
|
6765
6966
|
lastSize = stats.size;
|
|
6766
6967
|
}
|
|
6767
6968
|
const interval = setInterval(() => {
|
|
6768
|
-
if (
|
|
6769
|
-
const stats =
|
|
6969
|
+
if (fs28.existsSync(logPath)) {
|
|
6970
|
+
const stats = fs28.statSync(logPath);
|
|
6770
6971
|
if (stats.size > lastSize) {
|
|
6771
6972
|
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
6772
|
-
const fd =
|
|
6773
|
-
|
|
6774
|
-
|
|
6973
|
+
const fd = fs28.openSync(logPath, "r");
|
|
6974
|
+
fs28.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
6975
|
+
fs28.closeSync(fd);
|
|
6775
6976
|
const newContent = buffer.toString("utf-8");
|
|
6776
6977
|
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
6777
6978
|
setLogs((prev) => {
|
|
@@ -6808,10 +7009,10 @@ var init_App = __esm({
|
|
|
6808
7009
|
const handleConfigChange = useCallback3(() => {
|
|
6809
7010
|
refreshData();
|
|
6810
7011
|
}, [refreshData]);
|
|
6811
|
-
return /* @__PURE__ */
|
|
6812
|
-
/* @__PURE__ */
|
|
6813
|
-
/* @__PURE__ */
|
|
6814
|
-
activeTab === "overview" && /* @__PURE__ */
|
|
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(
|
|
6815
7016
|
Overview,
|
|
6816
7017
|
{
|
|
6817
7018
|
serverStatus: serverInfo,
|
|
@@ -6823,11 +7024,11 @@ var init_App = __esm({
|
|
|
6823
7024
|
logs
|
|
6824
7025
|
}
|
|
6825
7026
|
),
|
|
6826
|
-
activeTab === "logs" && /* @__PURE__ */
|
|
6827
|
-
activeTab === "tasks" && /* @__PURE__ */
|
|
6828
|
-
activeTab === "projects" && /* @__PURE__ */
|
|
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 })
|
|
6829
7030
|
] }),
|
|
6830
|
-
/* @__PURE__ */
|
|
7031
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 0, children: /* @__PURE__ */ jsx15(
|
|
6831
7032
|
StatusBoard,
|
|
6832
7033
|
{
|
|
6833
7034
|
exposedLabel: `${exposedProjects.length} / ${projects.length} projects`,
|
|
@@ -6845,7 +7046,7 @@ var init_App = __esm({
|
|
|
6845
7046
|
// src/mcp/commands/start.ts
|
|
6846
7047
|
import { confirm as confirm3, isCancel as isCancel5, text } from "@clack/prompts";
|
|
6847
7048
|
async function handleStartServer() {
|
|
6848
|
-
const
|
|
7049
|
+
const React16 = await import("react");
|
|
6849
7050
|
const { render } = await import("ink");
|
|
6850
7051
|
const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
|
|
6851
7052
|
const { ConfigProvider: ConfigProvider2 } = await Promise.resolve().then(() => (init_ConfigContext(), ConfigContext_exports));
|
|
@@ -6888,10 +7089,10 @@ async function handleStartServer() {
|
|
|
6888
7089
|
}
|
|
6889
7090
|
process.stdin.resume();
|
|
6890
7091
|
const app = render(
|
|
6891
|
-
|
|
7092
|
+
React16.createElement(
|
|
6892
7093
|
ConfigProvider2,
|
|
6893
7094
|
null,
|
|
6894
|
-
|
|
7095
|
+
React16.createElement(App2, {
|
|
6895
7096
|
initialPort,
|
|
6896
7097
|
onExit: () => {
|
|
6897
7098
|
}
|
|
@@ -6996,15 +7197,15 @@ __export(update_flow_exports, {
|
|
|
6996
7197
|
});
|
|
6997
7198
|
import { confirm as confirm5, spinner as spinner2, note as note6, outro as outro2, cancel as cancel2, isCancel as isCancel7 } from "@clack/prompts";
|
|
6998
7199
|
import pc8 from "picocolors";
|
|
6999
|
-
import * as
|
|
7000
|
-
import * as
|
|
7200
|
+
import * as fs29 from "fs";
|
|
7201
|
+
import * as path30 from "path";
|
|
7001
7202
|
import { stringify as stringify2, parse } from "yaml";
|
|
7002
7203
|
function backupFile(filePath) {
|
|
7003
|
-
if (!
|
|
7204
|
+
if (!fs29.existsSync(filePath)) return null;
|
|
7004
7205
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").split("T")[0] + "-" + Date.now();
|
|
7005
7206
|
const backupPath = `${filePath}.${timestamp}.bak`;
|
|
7006
7207
|
try {
|
|
7007
|
-
|
|
7208
|
+
fs29.copyFileSync(filePath, backupPath);
|
|
7008
7209
|
return backupPath;
|
|
7009
7210
|
} catch (e) {
|
|
7010
7211
|
console.error(`Failed to backup ${filePath}:`, e);
|
|
@@ -7014,9 +7215,9 @@ function backupFile(filePath) {
|
|
|
7014
7215
|
function getPackageVersion2() {
|
|
7015
7216
|
try {
|
|
7016
7217
|
const agentCoreDir = getAgentCoreDir();
|
|
7017
|
-
const packageJsonPath =
|
|
7018
|
-
if (
|
|
7019
|
-
return JSON.parse(
|
|
7218
|
+
const packageJsonPath = path30.join(path30.dirname(agentCoreDir), "package.json");
|
|
7219
|
+
if (fs29.existsSync(packageJsonPath)) {
|
|
7220
|
+
return JSON.parse(fs29.readFileSync(packageJsonPath, "utf8")).version;
|
|
7020
7221
|
}
|
|
7021
7222
|
} catch (e) {
|
|
7022
7223
|
}
|
|
@@ -7031,9 +7232,9 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
|
|
|
7031
7232
|
const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
|
|
7032
7233
|
const configFilePath = getConfigPath(workspacePath);
|
|
7033
7234
|
let currentSyncedVersion;
|
|
7034
|
-
if (
|
|
7235
|
+
if (fs29.existsSync(configFilePath)) {
|
|
7035
7236
|
try {
|
|
7036
|
-
const content =
|
|
7237
|
+
const content = fs29.readFileSync(configFilePath, "utf-8");
|
|
7037
7238
|
const config = parse(content);
|
|
7038
7239
|
currentSyncedVersion = config.last_synced_version;
|
|
7039
7240
|
} catch (e) {
|
|
@@ -7041,8 +7242,8 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
|
|
|
7041
7242
|
}
|
|
7042
7243
|
const driftReport = DriftService.checkDrift(dataPaths[0], currentSyncedVersion, runningVersion);
|
|
7043
7244
|
const ideTargets = [];
|
|
7044
|
-
if (
|
|
7045
|
-
const configContent =
|
|
7245
|
+
if (fs29.existsSync(configFilePath)) {
|
|
7246
|
+
const configContent = fs29.readFileSync(configFilePath, "utf-8");
|
|
7046
7247
|
if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
|
|
7047
7248
|
if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
|
|
7048
7249
|
if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
|
|
@@ -7051,14 +7252,14 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
|
|
|
7051
7252
|
const dirs = ["templates", "prompts", "docs"];
|
|
7052
7253
|
const updatedFiles = [];
|
|
7053
7254
|
for (const dir of dirs) {
|
|
7054
|
-
const srcDir =
|
|
7055
|
-
if (!
|
|
7255
|
+
const srcDir = path30.join(agentCoreDir, dir);
|
|
7256
|
+
if (!fs29.existsSync(srcDir)) continue;
|
|
7056
7257
|
const syncFiles = (src, rel) => {
|
|
7057
|
-
const entries =
|
|
7258
|
+
const entries = fs29.readdirSync(src, { withFileTypes: true });
|
|
7058
7259
|
for (const entry of entries) {
|
|
7059
|
-
const entrySrc =
|
|
7060
|
-
const entryRel =
|
|
7061
|
-
const entryDest =
|
|
7260
|
+
const entrySrc = path30.join(src, entry.name);
|
|
7261
|
+
const entryRel = path30.join(rel, entry.name);
|
|
7262
|
+
const entryDest = path30.join(dataPath, entryRel);
|
|
7062
7263
|
if (entry.isDirectory()) {
|
|
7063
7264
|
ensureDir(entryDest);
|
|
7064
7265
|
syncFiles(entrySrc, entryRel);
|
|
@@ -7066,8 +7267,8 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
|
|
|
7066
7267
|
if (driftReport.modifiedFiles.includes(entryRel)) {
|
|
7067
7268
|
backupFile(entryDest);
|
|
7068
7269
|
}
|
|
7069
|
-
ensureDir(
|
|
7070
|
-
|
|
7270
|
+
ensureDir(path30.dirname(entryDest));
|
|
7271
|
+
fs29.copyFileSync(entrySrc, entryDest);
|
|
7071
7272
|
updatedFiles.push(entryRel);
|
|
7072
7273
|
}
|
|
7073
7274
|
}
|
|
@@ -7078,12 +7279,12 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
|
|
|
7078
7279
|
DriftService.saveManifest(dataPath, manifest);
|
|
7079
7280
|
}
|
|
7080
7281
|
const rrceHome = customGlobalPath || getDefaultRRCEHome2();
|
|
7081
|
-
ensureDir(
|
|
7082
|
-
ensureDir(
|
|
7083
|
-
copyDirRecursive(
|
|
7084
|
-
copyDirRecursive(
|
|
7085
|
-
if (
|
|
7086
|
-
const configContent =
|
|
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");
|
|
7087
7288
|
if (configContent.includes("copilot: true")) {
|
|
7088
7289
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
7089
7290
|
ensureDir(copilotPath);
|
|
@@ -7105,21 +7306,21 @@ async function performUpdate(workspacePath, workspaceName, currentStorageMode, o
|
|
|
7105
7306
|
try {
|
|
7106
7307
|
const yaml = parse(configContent);
|
|
7107
7308
|
yaml.last_synced_version = runningVersion;
|
|
7108
|
-
|
|
7309
|
+
fs29.writeFileSync(configFilePath, stringify2(yaml));
|
|
7109
7310
|
} catch (e) {
|
|
7110
7311
|
console.error("Failed to update config.yaml version:", e);
|
|
7111
7312
|
}
|
|
7112
7313
|
}
|
|
7113
|
-
const mcpPath =
|
|
7114
|
-
if (
|
|
7314
|
+
const mcpPath = path30.join(rrceHome, "mcp.yaml");
|
|
7315
|
+
if (fs29.existsSync(mcpPath)) {
|
|
7115
7316
|
try {
|
|
7116
|
-
const content =
|
|
7317
|
+
const content = fs29.readFileSync(mcpPath, "utf-8");
|
|
7117
7318
|
const yaml = parse(content);
|
|
7118
7319
|
if (yaml.projects) {
|
|
7119
7320
|
const project = yaml.projects.find((p) => p.name === workspaceName);
|
|
7120
7321
|
if (project) {
|
|
7121
7322
|
project.last_synced_version = runningVersion;
|
|
7122
|
-
|
|
7323
|
+
fs29.writeFileSync(mcpPath, stringify2(yaml));
|
|
7123
7324
|
}
|
|
7124
7325
|
}
|
|
7125
7326
|
} catch (e) {
|
|
@@ -7155,9 +7356,9 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
|
7155
7356
|
const dataPaths = resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspacePath, customGlobalPath);
|
|
7156
7357
|
const configFilePath = getConfigPath(workspacePath);
|
|
7157
7358
|
let currentSyncedVersion;
|
|
7158
|
-
if (
|
|
7359
|
+
if (fs29.existsSync(configFilePath)) {
|
|
7159
7360
|
try {
|
|
7160
|
-
const content =
|
|
7361
|
+
const content = fs29.readFileSync(configFilePath, "utf-8");
|
|
7161
7362
|
const config = parse(content);
|
|
7162
7363
|
currentSyncedVersion = config.last_synced_version;
|
|
7163
7364
|
} catch (e) {
|
|
@@ -7181,8 +7382,8 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
|
7181
7382
|
` \u2022 docs/ (documentation)`
|
|
7182
7383
|
];
|
|
7183
7384
|
const ideTargets = [];
|
|
7184
|
-
if (
|
|
7185
|
-
const configContent =
|
|
7385
|
+
if (fs29.existsSync(configFilePath)) {
|
|
7386
|
+
const configContent = fs29.readFileSync(configFilePath, "utf-8");
|
|
7186
7387
|
if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
|
|
7187
7388
|
if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
|
|
7188
7389
|
if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
|
|
@@ -7211,14 +7412,14 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
7211
7412
|
const dirs = ["templates", "prompts", "docs"];
|
|
7212
7413
|
const updatedFiles = [];
|
|
7213
7414
|
for (const dir of dirs) {
|
|
7214
|
-
const srcDir =
|
|
7215
|
-
if (!
|
|
7415
|
+
const srcDir = path30.join(agentCoreDir, dir);
|
|
7416
|
+
if (!fs29.existsSync(srcDir)) continue;
|
|
7216
7417
|
const syncFiles = (src, rel) => {
|
|
7217
|
-
const entries =
|
|
7418
|
+
const entries = fs29.readdirSync(src, { withFileTypes: true });
|
|
7218
7419
|
for (const entry of entries) {
|
|
7219
|
-
const entrySrc =
|
|
7220
|
-
const entryRel =
|
|
7221
|
-
const entryDest =
|
|
7420
|
+
const entrySrc = path30.join(src, entry.name);
|
|
7421
|
+
const entryRel = path30.join(rel, entry.name);
|
|
7422
|
+
const entryDest = path30.join(dataPath, entryRel);
|
|
7222
7423
|
if (entry.isDirectory()) {
|
|
7223
7424
|
ensureDir(entryDest);
|
|
7224
7425
|
syncFiles(entrySrc, entryRel);
|
|
@@ -7226,8 +7427,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
7226
7427
|
if (driftReport.modifiedFiles.includes(entryRel)) {
|
|
7227
7428
|
backupFile(entryDest);
|
|
7228
7429
|
}
|
|
7229
|
-
ensureDir(
|
|
7230
|
-
|
|
7430
|
+
ensureDir(path30.dirname(entryDest));
|
|
7431
|
+
fs29.copyFileSync(entrySrc, entryDest);
|
|
7231
7432
|
updatedFiles.push(entryRel);
|
|
7232
7433
|
}
|
|
7233
7434
|
}
|
|
@@ -7238,12 +7439,12 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
7238
7439
|
DriftService.saveManifest(dataPath, manifest);
|
|
7239
7440
|
}
|
|
7240
7441
|
const rrceHome = customGlobalPath || getDefaultRRCEHome2();
|
|
7241
|
-
ensureDir(
|
|
7242
|
-
ensureDir(
|
|
7243
|
-
copyDirRecursive(
|
|
7244
|
-
copyDirRecursive(
|
|
7245
|
-
if (
|
|
7246
|
-
const configContent =
|
|
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");
|
|
7247
7448
|
if (configContent.includes("copilot: true")) {
|
|
7248
7449
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
7249
7450
|
ensureDir(copilotPath);
|
|
@@ -7265,21 +7466,21 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
7265
7466
|
try {
|
|
7266
7467
|
const yaml = parse(configContent);
|
|
7267
7468
|
yaml.last_synced_version = runningVersion;
|
|
7268
|
-
|
|
7469
|
+
fs29.writeFileSync(configFilePath, stringify2(yaml));
|
|
7269
7470
|
} catch (e) {
|
|
7270
7471
|
console.error("Failed to update config.yaml version:", e);
|
|
7271
7472
|
}
|
|
7272
7473
|
}
|
|
7273
|
-
const mcpPath =
|
|
7274
|
-
if (
|
|
7474
|
+
const mcpPath = path30.join(rrceHome, "mcp.yaml");
|
|
7475
|
+
if (fs29.existsSync(mcpPath)) {
|
|
7275
7476
|
try {
|
|
7276
|
-
const content =
|
|
7477
|
+
const content = fs29.readFileSync(mcpPath, "utf-8");
|
|
7277
7478
|
const yaml = parse(content);
|
|
7278
7479
|
if (yaml.projects) {
|
|
7279
7480
|
const project = yaml.projects.find((p) => p.name === workspaceName);
|
|
7280
7481
|
if (project) {
|
|
7281
7482
|
project.last_synced_version = runningVersion;
|
|
7282
|
-
|
|
7483
|
+
fs29.writeFileSync(mcpPath, stringify2(yaml));
|
|
7283
7484
|
}
|
|
7284
7485
|
}
|
|
7285
7486
|
} catch (e) {
|
|
@@ -7314,8 +7515,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
7314
7515
|
}
|
|
7315
7516
|
}
|
|
7316
7517
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
7317
|
-
const globalPath =
|
|
7318
|
-
const workspacePath =
|
|
7518
|
+
const globalPath = path30.join(customGlobalPath, "workspaces", workspaceName);
|
|
7519
|
+
const workspacePath = path30.join(workspaceRoot, ".rrce-workflow");
|
|
7319
7520
|
switch (mode) {
|
|
7320
7521
|
case "global":
|
|
7321
7522
|
return [globalPath];
|
|
@@ -7338,8 +7539,8 @@ var init_update_flow = __esm({
|
|
|
7338
7539
|
// src/commands/wizard/index.ts
|
|
7339
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";
|
|
7340
7541
|
import pc13 from "picocolors";
|
|
7341
|
-
import * as
|
|
7342
|
-
import * as
|
|
7542
|
+
import * as fs33 from "fs";
|
|
7543
|
+
import * as path32 from "path";
|
|
7343
7544
|
import { parse as parse2 } from "yaml";
|
|
7344
7545
|
|
|
7345
7546
|
// src/lib/git.ts
|
|
@@ -7481,22 +7682,22 @@ async function promptConfirmation() {
|
|
|
7481
7682
|
init_paths();
|
|
7482
7683
|
init_prompts();
|
|
7483
7684
|
init_utils();
|
|
7484
|
-
import * as
|
|
7485
|
-
import * as
|
|
7685
|
+
import * as fs11 from "fs";
|
|
7686
|
+
import * as path13 from "path";
|
|
7486
7687
|
import pc4 from "picocolors";
|
|
7487
7688
|
import { note as note2 } from "@clack/prompts";
|
|
7488
7689
|
|
|
7489
7690
|
// src/commands/wizard/vscode.ts
|
|
7490
7691
|
init_paths();
|
|
7491
7692
|
init_detection();
|
|
7492
|
-
import * as
|
|
7493
|
-
import * as
|
|
7693
|
+
import * as fs9 from "fs";
|
|
7694
|
+
import * as path10 from "path";
|
|
7494
7695
|
function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, customGlobalPath) {
|
|
7495
|
-
const workspaceFilePath =
|
|
7696
|
+
const workspaceFilePath = path10.join(workspacePath, `${workspaceName}.code-workspace`);
|
|
7496
7697
|
let workspace;
|
|
7497
|
-
if (
|
|
7698
|
+
if (fs9.existsSync(workspaceFilePath)) {
|
|
7498
7699
|
try {
|
|
7499
|
-
const content =
|
|
7700
|
+
const content = fs9.readFileSync(workspaceFilePath, "utf-8");
|
|
7500
7701
|
workspace = JSON.parse(content);
|
|
7501
7702
|
} catch {
|
|
7502
7703
|
workspace = { folders: [], settings: {} };
|
|
@@ -7529,7 +7730,7 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
|
|
|
7529
7730
|
for (const project of projects) {
|
|
7530
7731
|
const sourceLabel = project.source === "global" ? "global" : "local";
|
|
7531
7732
|
const folderPath = project.dataPath;
|
|
7532
|
-
if (
|
|
7733
|
+
if (fs9.existsSync(folderPath)) {
|
|
7533
7734
|
referenceFolderPaths.push(folderPath);
|
|
7534
7735
|
workspace.folders.push({
|
|
7535
7736
|
path: folderPath,
|
|
@@ -7541,8 +7742,8 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
|
|
|
7541
7742
|
const projectNames = linkedProjects;
|
|
7542
7743
|
const rrceHome = customGlobalPath || getRRCEHome();
|
|
7543
7744
|
for (const projectName of projectNames) {
|
|
7544
|
-
const folderPath =
|
|
7545
|
-
if (
|
|
7745
|
+
const folderPath = path10.join(rrceHome, "workspaces", projectName);
|
|
7746
|
+
if (fs9.existsSync(folderPath)) {
|
|
7546
7747
|
referenceFolderPaths.push(folderPath);
|
|
7547
7748
|
workspace.folders.push({
|
|
7548
7749
|
path: folderPath,
|
|
@@ -7568,23 +7769,23 @@ function generateVSCodeWorkspace(workspacePath, workspaceName, linkedProjects, c
|
|
|
7568
7769
|
...readonlyPatterns
|
|
7569
7770
|
};
|
|
7570
7771
|
}
|
|
7571
|
-
|
|
7772
|
+
fs9.writeFileSync(workspaceFilePath, JSON.stringify(workspace, null, 2));
|
|
7572
7773
|
}
|
|
7573
7774
|
|
|
7574
7775
|
// src/commands/wizard/setup-actions.ts
|
|
7575
7776
|
init_install();
|
|
7576
7777
|
function detectExistingProject(workspacePath, workspaceName, globalPath) {
|
|
7577
7778
|
const rrceHome = globalPath || getDefaultRRCEHome2();
|
|
7578
|
-
const globalConfigPath =
|
|
7579
|
-
const workspaceConfigPath =
|
|
7779
|
+
const globalConfigPath = path13.join(rrceHome, "workspaces", workspaceName, "config.yaml");
|
|
7780
|
+
const workspaceConfigPath = path13.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
7580
7781
|
const hasOpenCodeAgents = checkForRRCEAgents();
|
|
7581
|
-
if (
|
|
7782
|
+
if (fs11.existsSync(globalConfigPath)) {
|
|
7582
7783
|
return {
|
|
7583
7784
|
isExisting: true,
|
|
7584
7785
|
currentMode: "global",
|
|
7585
7786
|
configPath: globalConfigPath
|
|
7586
7787
|
};
|
|
7587
|
-
} else if (
|
|
7788
|
+
} else if (fs11.existsSync(workspaceConfigPath)) {
|
|
7588
7789
|
return {
|
|
7589
7790
|
isExisting: true,
|
|
7590
7791
|
currentMode: "workspace",
|
|
@@ -7604,9 +7805,9 @@ function detectExistingProject(workspacePath, workspaceName, globalPath) {
|
|
|
7604
7805
|
};
|
|
7605
7806
|
}
|
|
7606
7807
|
function checkForRRCEAgents() {
|
|
7607
|
-
if (!
|
|
7808
|
+
if (!fs11.existsSync(OPENCODE_CONFIG)) return false;
|
|
7608
7809
|
try {
|
|
7609
|
-
const config = JSON.parse(
|
|
7810
|
+
const config = JSON.parse(fs11.readFileSync(OPENCODE_CONFIG, "utf8"));
|
|
7610
7811
|
const agentKeys = Object.keys(config.agent || config.agents || {});
|
|
7611
7812
|
return agentKeys.some((key) => key.startsWith("rrce_"));
|
|
7612
7813
|
} catch {
|
|
@@ -7616,23 +7817,23 @@ function checkForRRCEAgents() {
|
|
|
7616
7817
|
function createDirectoryStructure(dataPaths) {
|
|
7617
7818
|
for (const dataPath of dataPaths) {
|
|
7618
7819
|
ensureDir(dataPath);
|
|
7619
|
-
ensureDir(
|
|
7620
|
-
ensureDir(
|
|
7621
|
-
ensureDir(
|
|
7622
|
-
ensureDir(
|
|
7820
|
+
ensureDir(path13.join(dataPath, "knowledge"));
|
|
7821
|
+
ensureDir(path13.join(dataPath, "refs"));
|
|
7822
|
+
ensureDir(path13.join(dataPath, "tasks"));
|
|
7823
|
+
ensureDir(path13.join(dataPath, "templates"));
|
|
7623
7824
|
}
|
|
7624
7825
|
}
|
|
7625
7826
|
async function installAgentPrompts(config, workspacePath, dataPaths) {
|
|
7626
7827
|
const agentCoreDir = getAgentCoreDir();
|
|
7627
7828
|
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
7628
|
-
copyDirToAllStoragePaths(
|
|
7629
|
-
copyDirToAllStoragePaths(
|
|
7630
|
-
copyDirToAllStoragePaths(
|
|
7829
|
+
copyDirToAllStoragePaths(path13.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
7830
|
+
copyDirToAllStoragePaths(path13.join(agentCoreDir, "prompts"), "prompts", dataPaths);
|
|
7831
|
+
copyDirToAllStoragePaths(path13.join(agentCoreDir, "docs"), "docs", dataPaths);
|
|
7631
7832
|
const rrceHome = config.globalPath || getDefaultRRCEHome2();
|
|
7632
|
-
ensureDir(
|
|
7633
|
-
ensureDir(
|
|
7634
|
-
copyDirRecursive(
|
|
7635
|
-
copyDirRecursive(
|
|
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"));
|
|
7636
7837
|
const needsIDEPrompts = config.storageMode === "workspace" && (config.tools.includes("copilot") || config.tools.includes("antigravity")) || config.tools.includes("opencode");
|
|
7637
7838
|
if (needsIDEPrompts) {
|
|
7638
7839
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
@@ -7661,11 +7862,11 @@ function createWorkspaceConfig(config, workspacePath, workspaceName) {
|
|
|
7661
7862
|
let configPath;
|
|
7662
7863
|
if (config.storageMode === "global") {
|
|
7663
7864
|
const rrceHome = config.globalPath || getDefaultRRCEHome2();
|
|
7664
|
-
configPath =
|
|
7865
|
+
configPath = path13.join(rrceHome, "workspaces", workspaceName, "config.yaml");
|
|
7665
7866
|
} else {
|
|
7666
|
-
configPath =
|
|
7867
|
+
configPath = path13.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
7667
7868
|
}
|
|
7668
|
-
ensureDir(
|
|
7869
|
+
ensureDir(path13.dirname(configPath));
|
|
7669
7870
|
let content = `# RRCE-Workflow Configuration
|
|
7670
7871
|
version: 1
|
|
7671
7872
|
|
|
@@ -7701,7 +7902,7 @@ linked_projects:
|
|
|
7701
7902
|
`;
|
|
7702
7903
|
});
|
|
7703
7904
|
}
|
|
7704
|
-
|
|
7905
|
+
fs11.writeFileSync(configPath, content);
|
|
7705
7906
|
}
|
|
7706
7907
|
async function registerWithMCP(config, workspacePath, workspaceName) {
|
|
7707
7908
|
if (!config.exposeToMCP) return;
|
|
@@ -7728,8 +7929,8 @@ You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
|
|
|
7728
7929
|
}
|
|
7729
7930
|
}
|
|
7730
7931
|
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
7731
|
-
const globalPath =
|
|
7732
|
-
const workspacePath =
|
|
7932
|
+
const globalPath = path13.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
|
|
7933
|
+
const workspacePath = path13.join(workspaceRoot, ".rrce-workflow");
|
|
7733
7934
|
switch (mode) {
|
|
7734
7935
|
case "global":
|
|
7735
7936
|
return [globalPath];
|
|
@@ -8016,7 +8217,7 @@ async function handlePostSetup(config, workspacePath, workspaceName, linkedProje
|
|
|
8016
8217
|
init_paths();
|
|
8017
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";
|
|
8018
8219
|
import pc10 from "picocolors";
|
|
8019
|
-
import * as
|
|
8220
|
+
import * as fs30 from "fs";
|
|
8020
8221
|
init_detection();
|
|
8021
8222
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
8022
8223
|
const projects = scanForProjects({
|
|
@@ -8055,7 +8256,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
8055
8256
|
const s = spinner4();
|
|
8056
8257
|
s.start("Linking projects");
|
|
8057
8258
|
const configFilePath = getConfigPath(workspacePath);
|
|
8058
|
-
let configContent =
|
|
8259
|
+
let configContent = fs30.readFileSync(configFilePath, "utf-8");
|
|
8059
8260
|
if (configContent.includes("linked_projects:")) {
|
|
8060
8261
|
const lines = configContent.split("\n");
|
|
8061
8262
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -8082,7 +8283,7 @@ linked_projects:
|
|
|
8082
8283
|
`;
|
|
8083
8284
|
});
|
|
8084
8285
|
}
|
|
8085
|
-
|
|
8286
|
+
fs30.writeFileSync(configFilePath, configContent);
|
|
8086
8287
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
8087
8288
|
s.stop("Projects linked");
|
|
8088
8289
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
@@ -8118,15 +8319,15 @@ init_paths();
|
|
|
8118
8319
|
init_utils();
|
|
8119
8320
|
import { confirm as confirm8, spinner as spinner5, note as note9, outro as outro5, cancel as cancel5, isCancel as isCancel10 } from "@clack/prompts";
|
|
8120
8321
|
import pc11 from "picocolors";
|
|
8121
|
-
import * as
|
|
8122
|
-
import * as
|
|
8322
|
+
import * as fs31 from "fs";
|
|
8323
|
+
import * as path31 from "path";
|
|
8123
8324
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
8124
8325
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
8125
8326
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
8126
|
-
const globalPath =
|
|
8327
|
+
const globalPath = path31.join(customGlobalPath, "workspaces", workspaceName);
|
|
8127
8328
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
8128
8329
|
const existingDirs = subdirs.filter(
|
|
8129
|
-
(dir) =>
|
|
8330
|
+
(dir) => fs31.existsSync(path31.join(localPath, dir))
|
|
8130
8331
|
);
|
|
8131
8332
|
if (existingDirs.length === 0) {
|
|
8132
8333
|
outro5(pc11.yellow("No data found in workspace storage to sync."));
|
|
@@ -8152,8 +8353,8 @@ Destination: ${pc11.cyan(globalPath)}`,
|
|
|
8152
8353
|
try {
|
|
8153
8354
|
ensureDir(globalPath);
|
|
8154
8355
|
for (const dir of existingDirs) {
|
|
8155
|
-
const srcDir =
|
|
8156
|
-
const destDir =
|
|
8356
|
+
const srcDir = path31.join(localPath, dir);
|
|
8357
|
+
const destDir = path31.join(globalPath, dir);
|
|
8157
8358
|
ensureDir(destDir);
|
|
8158
8359
|
copyDirRecursive(srcDir, destDir);
|
|
8159
8360
|
}
|
|
@@ -8181,7 +8382,7 @@ init_update_flow();
|
|
|
8181
8382
|
// src/commands/wizard/delete-flow.ts
|
|
8182
8383
|
import { multiselect as multiselect5, confirm as confirm9, spinner as spinner6, note as note10, cancel as cancel6, isCancel as isCancel11 } from "@clack/prompts";
|
|
8183
8384
|
import pc12 from "picocolors";
|
|
8184
|
-
import * as
|
|
8385
|
+
import * as fs32 from "fs";
|
|
8185
8386
|
init_detection();
|
|
8186
8387
|
init_config();
|
|
8187
8388
|
async function runDeleteGlobalProjectFlow(availableProjects) {
|
|
@@ -8225,8 +8426,8 @@ Are you sure?`,
|
|
|
8225
8426
|
for (const projectName of projectsToDelete) {
|
|
8226
8427
|
const project = globalProjects.find((p) => p.name === projectName);
|
|
8227
8428
|
if (!project) continue;
|
|
8228
|
-
if (
|
|
8229
|
-
|
|
8429
|
+
if (fs32.existsSync(project.dataPath)) {
|
|
8430
|
+
fs32.rmSync(project.dataPath, { recursive: true, force: true });
|
|
8230
8431
|
}
|
|
8231
8432
|
const newConfig = removeProjectConfig(mcpConfig, projectName);
|
|
8232
8433
|
configChanged = true;
|
|
@@ -8248,9 +8449,9 @@ init_config();
|
|
|
8248
8449
|
function getPackageVersion3() {
|
|
8249
8450
|
try {
|
|
8250
8451
|
const agentCoreDir = getAgentCoreDir();
|
|
8251
|
-
const packageJsonPath =
|
|
8252
|
-
if (
|
|
8253
|
-
return JSON.parse(
|
|
8452
|
+
const packageJsonPath = path32.join(path32.dirname(agentCoreDir), "package.json");
|
|
8453
|
+
if (fs33.existsSync(packageJsonPath)) {
|
|
8454
|
+
return JSON.parse(fs33.readFileSync(packageJsonPath, "utf8")).version;
|
|
8254
8455
|
}
|
|
8255
8456
|
} catch (e) {
|
|
8256
8457
|
}
|
|
@@ -8258,9 +8459,9 @@ function getPackageVersion3() {
|
|
|
8258
8459
|
}
|
|
8259
8460
|
function getLastSyncedVersion(workspacePath, workspaceName) {
|
|
8260
8461
|
const configFilePath = getConfigPath(workspacePath);
|
|
8261
|
-
if (
|
|
8462
|
+
if (fs33.existsSync(configFilePath)) {
|
|
8262
8463
|
try {
|
|
8263
|
-
const content =
|
|
8464
|
+
const content = fs33.readFileSync(configFilePath, "utf-8");
|
|
8264
8465
|
const config = parse2(content);
|
|
8265
8466
|
if (config.last_synced_version) {
|
|
8266
8467
|
return config.last_synced_version;
|
|
@@ -8269,10 +8470,10 @@ function getLastSyncedVersion(workspacePath, workspaceName) {
|
|
|
8269
8470
|
}
|
|
8270
8471
|
}
|
|
8271
8472
|
const rrceHome = getEffectiveRRCEHome(workspacePath) || getDefaultRRCEHome2();
|
|
8272
|
-
const mcpPath =
|
|
8273
|
-
if (
|
|
8473
|
+
const mcpPath = path32.join(rrceHome, "mcp.yaml");
|
|
8474
|
+
if (fs33.existsSync(mcpPath)) {
|
|
8274
8475
|
try {
|
|
8275
|
-
const content =
|
|
8476
|
+
const content = fs33.readFileSync(mcpPath, "utf-8");
|
|
8276
8477
|
const config = parse2(content);
|
|
8277
8478
|
const project = config.projects?.find((p) => p.name === workspaceName);
|
|
8278
8479
|
if (project?.last_synced_version) {
|
|
@@ -8342,11 +8543,11 @@ Workspace: ${pc13.bold(workspaceName)}`,
|
|
|
8342
8543
|
workspacePath
|
|
8343
8544
|
});
|
|
8344
8545
|
const configFilePath = getConfigPath(workspacePath);
|
|
8345
|
-
let isAlreadyConfigured =
|
|
8546
|
+
let isAlreadyConfigured = fs33.existsSync(configFilePath);
|
|
8346
8547
|
let currentStorageMode = null;
|
|
8347
8548
|
if (isAlreadyConfigured) {
|
|
8348
8549
|
try {
|
|
8349
|
-
const configContent =
|
|
8550
|
+
const configContent = fs33.readFileSync(configFilePath, "utf-8");
|
|
8350
8551
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
8351
8552
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
8352
8553
|
} catch {
|
|
@@ -8363,7 +8564,7 @@ Workspace: ${pc13.bold(workspaceName)}`,
|
|
|
8363
8564
|
}
|
|
8364
8565
|
}
|
|
8365
8566
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
8366
|
-
const hasLocalData =
|
|
8567
|
+
const hasLocalData = fs33.existsSync(localDataPath);
|
|
8367
8568
|
if (isAlreadyConfigured) {
|
|
8368
8569
|
const continueToMenu = await checkAndPromptUpdate(workspacePath, workspaceName, currentStorageMode);
|
|
8369
8570
|
if (!continueToMenu) {
|