rrce-workflow 0.2.43 → 0.2.44
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.
|
@@ -50,6 +50,7 @@ Do not proceed with execution until all prerequisites are satisfied.
|
|
|
50
50
|
Mission
|
|
51
51
|
- Implement the scoped work, keeping quality high and feedback loops short.
|
|
52
52
|
- Update stakeholders on progress and record verifications so outcomes are auditable.
|
|
53
|
+
- Use the `search_knowledge` tool (if available) to find internal API usage examples or coding patterns.
|
|
53
54
|
|
|
54
55
|
Non-Negotiables
|
|
55
56
|
1. Read `{{RRCE_DATA}}/tasks/{{TASK_SLUG}}/meta.json` and the latest plan before touching code.
|
|
@@ -162,6 +162,10 @@ Workflow Steps
|
|
|
162
162
|
7. Save to `{{RRCE_DATA}}/knowledge/project-context.md`.
|
|
163
163
|
8. Update `{{RRCE_DATA}}/workspace.json` with project metadata.
|
|
164
164
|
9. Log changes made (new sections, updated sections, removed outdated info).
|
|
165
|
+
10. **Semantic Indexing**: If the `index_knowledge` tool is available, run it:
|
|
166
|
+
- Tool: `index_knowledge`
|
|
167
|
+
- Args: `{ project: "{{WORKSPACE_NAME}}" }`
|
|
168
|
+
- This ensures the new context is immediately searchable.
|
|
165
169
|
|
|
166
170
|
Deliverable
|
|
167
171
|
- File: `{{RRCE_DATA}}/knowledge/project-context.md`
|
|
@@ -42,6 +42,7 @@ Do not proceed with planning until both prerequisites are satisfied.
|
|
|
42
42
|
Mission
|
|
43
43
|
- Convert the Research brief into a concrete, prioritized plan that the Executor can follow with minimal ambiguity.
|
|
44
44
|
- Maintain cohesive project knowledge within the RRCE cache, ensuring future agents inherit accurate context.
|
|
45
|
+
- Use the `search_knowledge` tool (if available) to validate architectural alignment and find relevant prior art.
|
|
45
46
|
|
|
46
47
|
Non-Negotiables
|
|
47
48
|
1. Review `{{RRCE_DATA}}/tasks/{{TASK_SLUG}}/meta.json`, the research artifact, and relevant entries under `{{RRCE_DATA}}/knowledge` before planning.
|
|
@@ -66,6 +66,9 @@ Workflow
|
|
|
66
66
|
- Remove outdated sections or entire files once you verify the information no longer applies.
|
|
67
67
|
4. Ensure cross-references (links to tasks, commits, or other knowledge files) point to current resources.
|
|
68
68
|
5. Summarize any unresolved questions or future sync needs at the bottom of the modified file(s) under a `Checklist` heading.
|
|
69
|
+
6. **Semantic Indexing**: If any knowledge files were modified or created, and the `index_knowledge` tool is available, run it to keep the search index current:
|
|
70
|
+
- Tool: `index_knowledge`
|
|
71
|
+
- Args: `{ project: "{{WORKSPACE_NAME}}" }`
|
|
69
72
|
|
|
70
73
|
Deliverable
|
|
71
74
|
- Updated `{{RRCE_DATA}}/knowledge/*` files that accurately reflect the present project state, each carrying the latest `Updated:` marker and lean checklist.
|
package/dist/index.js
CHANGED
|
@@ -877,6 +877,7 @@ function parseMCPConfig(content) {
|
|
|
877
877
|
let currentSection = null;
|
|
878
878
|
let currentProject = null;
|
|
879
879
|
let inPermissions = false;
|
|
880
|
+
let inSemanticSearch = false;
|
|
880
881
|
for (const line of lines) {
|
|
881
882
|
const trimmed = line.trim();
|
|
882
883
|
if (trimmed.startsWith("#") || trimmed === "") continue;
|
|
@@ -884,18 +885,21 @@ function parseMCPConfig(content) {
|
|
|
884
885
|
currentSection = "server";
|
|
885
886
|
currentProject = null;
|
|
886
887
|
inPermissions = false;
|
|
888
|
+
inSemanticSearch = false;
|
|
887
889
|
continue;
|
|
888
890
|
}
|
|
889
891
|
if (line.match(/^defaults:/)) {
|
|
890
892
|
currentSection = "defaults";
|
|
891
893
|
currentProject = null;
|
|
892
894
|
inPermissions = false;
|
|
895
|
+
inSemanticSearch = false;
|
|
893
896
|
continue;
|
|
894
897
|
}
|
|
895
898
|
if (line.match(/^projects:/)) {
|
|
896
899
|
currentSection = "projects";
|
|
897
900
|
currentProject = null;
|
|
898
901
|
inPermissions = false;
|
|
902
|
+
inSemanticSearch = false;
|
|
899
903
|
continue;
|
|
900
904
|
}
|
|
901
905
|
if (currentSection === "server") {
|
|
@@ -955,6 +959,20 @@ function parseMCPConfig(content) {
|
|
|
955
959
|
const refsMatch = trimmed.match(/^refs:\s*(true|false)/);
|
|
956
960
|
if (refsMatch) currentProject.permissions.refs = refsMatch[1] === "true";
|
|
957
961
|
}
|
|
962
|
+
if (trimmed === "semanticSearch:") {
|
|
963
|
+
inSemanticSearch = true;
|
|
964
|
+
inPermissions = false;
|
|
965
|
+
if (!currentProject.semanticSearch) {
|
|
966
|
+
currentProject.semanticSearch = { enabled: false };
|
|
967
|
+
}
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
if (inSemanticSearch && currentProject.semanticSearch) {
|
|
971
|
+
const enabledMatch = trimmed.match(/^enabled:\s*(true|false)/);
|
|
972
|
+
if (enabledMatch) currentProject.semanticSearch.enabled = enabledMatch[1] === "true";
|
|
973
|
+
const modelMatch = trimmed.match(/^model:\s*["']?([^"'\n]+)["']?/);
|
|
974
|
+
if (modelMatch) currentProject.semanticSearch.model = modelMatch[1].trim();
|
|
975
|
+
}
|
|
958
976
|
}
|
|
959
977
|
}
|
|
960
978
|
}
|
|
@@ -991,7 +1009,17 @@ projects:
|
|
|
991
1009
|
`;
|
|
992
1010
|
}
|
|
993
1011
|
content += ` expose: ${project.expose}
|
|
994
|
-
|
|
1012
|
+
`;
|
|
1013
|
+
if (project.semanticSearch) {
|
|
1014
|
+
content += ` semanticSearch:
|
|
1015
|
+
enabled: ${project.semanticSearch.enabled}
|
|
1016
|
+
`;
|
|
1017
|
+
if (project.semanticSearch.model) {
|
|
1018
|
+
content += ` model: "${project.semanticSearch.model}"
|
|
1019
|
+
`;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
content += ` permissions:
|
|
995
1023
|
knowledge: ${project.permissions.knowledge}
|
|
996
1024
|
tasks: ${project.permissions.tasks}
|
|
997
1025
|
refs: ${project.permissions.refs}
|
|
@@ -1000,7 +1028,7 @@ projects:
|
|
|
1000
1028
|
}
|
|
1001
1029
|
return content;
|
|
1002
1030
|
}
|
|
1003
|
-
function setProjectConfig(config, name, expose, permissions, projectPath) {
|
|
1031
|
+
function setProjectConfig(config, name, expose, permissions, projectPath, semanticSearch) {
|
|
1004
1032
|
let existing = config.projects.find((p) => {
|
|
1005
1033
|
if (projectPath && p.path) {
|
|
1006
1034
|
return p.path === projectPath;
|
|
@@ -1021,12 +1049,16 @@ function setProjectConfig(config, name, expose, permissions, projectPath) {
|
|
|
1021
1049
|
if (permissions) {
|
|
1022
1050
|
existing.permissions = { ...existing.permissions, ...permissions };
|
|
1023
1051
|
}
|
|
1052
|
+
if (semanticSearch) {
|
|
1053
|
+
existing.semanticSearch = semanticSearch;
|
|
1054
|
+
}
|
|
1024
1055
|
} else {
|
|
1025
1056
|
config.projects.push({
|
|
1026
1057
|
name,
|
|
1027
1058
|
path: projectPath,
|
|
1028
1059
|
expose,
|
|
1029
|
-
permissions: permissions ? { ...DEFAULT_PERMISSIONS, ...permissions } : { ...DEFAULT_PERMISSIONS }
|
|
1060
|
+
permissions: permissions ? { ...DEFAULT_PERMISSIONS, ...permissions } : { ...DEFAULT_PERMISSIONS },
|
|
1061
|
+
semanticSearch
|
|
1030
1062
|
});
|
|
1031
1063
|
}
|
|
1032
1064
|
return config;
|
|
@@ -1128,9 +1160,199 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
1128
1160
|
}
|
|
1129
1161
|
});
|
|
1130
1162
|
|
|
1131
|
-
// src/mcp/
|
|
1163
|
+
// src/mcp/services/rag.ts
|
|
1164
|
+
import { pipeline } from "@xenova/transformers";
|
|
1132
1165
|
import * as fs9 from "fs";
|
|
1133
1166
|
import * as path10 from "path";
|
|
1167
|
+
var INDEX_VERSION, DEFAULT_MODEL, RAGService;
|
|
1168
|
+
var init_rag = __esm({
|
|
1169
|
+
"src/mcp/services/rag.ts"() {
|
|
1170
|
+
"use strict";
|
|
1171
|
+
init_logger();
|
|
1172
|
+
INDEX_VERSION = "1.0.0";
|
|
1173
|
+
DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
1174
|
+
RAGService = class {
|
|
1175
|
+
pipe = null;
|
|
1176
|
+
modelName;
|
|
1177
|
+
indexPath;
|
|
1178
|
+
index = null;
|
|
1179
|
+
lastAccess = 0;
|
|
1180
|
+
constructor(indexPath, modelName = DEFAULT_MODEL) {
|
|
1181
|
+
this.indexPath = indexPath;
|
|
1182
|
+
this.modelName = modelName;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Lazy load the model
|
|
1186
|
+
*/
|
|
1187
|
+
async getPipeline() {
|
|
1188
|
+
if (!this.pipe) {
|
|
1189
|
+
logger.info(`RAG: Initializing model ${this.modelName}...`);
|
|
1190
|
+
try {
|
|
1191
|
+
this.pipe = await pipeline("feature-extraction", this.modelName);
|
|
1192
|
+
logger.info(`RAG: Model ${this.modelName} initialized successfully.`);
|
|
1193
|
+
} catch (error) {
|
|
1194
|
+
logger.error(`RAG: Failed to initialize model ${this.modelName}`, error);
|
|
1195
|
+
throw error;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
this.lastAccess = Date.now();
|
|
1199
|
+
return this.pipe;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Load index from disk
|
|
1203
|
+
*/
|
|
1204
|
+
loadIndex() {
|
|
1205
|
+
if (this.index) return;
|
|
1206
|
+
if (fs9.existsSync(this.indexPath)) {
|
|
1207
|
+
try {
|
|
1208
|
+
const data = fs9.readFileSync(this.indexPath, "utf-8");
|
|
1209
|
+
this.index = JSON.parse(data);
|
|
1210
|
+
logger.info(`RAG: Loaded index from ${this.indexPath} with ${this.index?.chunks.length} chunks.`);
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
logger.error(`RAG: Failed to load index from ${this.indexPath}`, error);
|
|
1213
|
+
this.index = {
|
|
1214
|
+
version: INDEX_VERSION,
|
|
1215
|
+
baseModel: this.modelName,
|
|
1216
|
+
chunks: []
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
} else {
|
|
1220
|
+
this.index = {
|
|
1221
|
+
version: INDEX_VERSION,
|
|
1222
|
+
baseModel: this.modelName,
|
|
1223
|
+
chunks: []
|
|
1224
|
+
};
|
|
1225
|
+
logger.info(`RAG: Created new empty index at ${this.indexPath}`);
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Save index to disk
|
|
1230
|
+
*/
|
|
1231
|
+
saveIndex() {
|
|
1232
|
+
if (!this.index) return;
|
|
1233
|
+
try {
|
|
1234
|
+
const dir = path10.dirname(this.indexPath);
|
|
1235
|
+
if (!fs9.existsSync(dir)) {
|
|
1236
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
1237
|
+
}
|
|
1238
|
+
fs9.writeFileSync(this.indexPath, JSON.stringify(this.index, null, 2));
|
|
1239
|
+
logger.info(`RAG: Saved index to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
logger.error(`RAG: Failed to save index to ${this.indexPath}`, error);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Generate embedding for text
|
|
1246
|
+
*/
|
|
1247
|
+
async generateEmbedding(text3) {
|
|
1248
|
+
const pipe = await this.getPipeline();
|
|
1249
|
+
try {
|
|
1250
|
+
const output = await pipe(text3, { pooling: "mean", normalize: true });
|
|
1251
|
+
return Array.from(output.data);
|
|
1252
|
+
} catch (error) {
|
|
1253
|
+
logger.error("RAG: Error generating embedding", error);
|
|
1254
|
+
throw error;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Index a file
|
|
1259
|
+
*/
|
|
1260
|
+
async indexFile(filePath, content) {
|
|
1261
|
+
this.loadIndex();
|
|
1262
|
+
if (!this.index) throw new Error("Index not initialized");
|
|
1263
|
+
logger.info(`RAG: Indexing file ${filePath}`);
|
|
1264
|
+
this.index.chunks = this.index.chunks.filter((c) => c.filePath !== filePath);
|
|
1265
|
+
const chunks = this.chunkContent(content);
|
|
1266
|
+
for (const chunkText of chunks) {
|
|
1267
|
+
const embedding = await this.generateEmbedding(chunkText);
|
|
1268
|
+
this.index.chunks.push({
|
|
1269
|
+
id: `${filePath}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
1270
|
+
filePath,
|
|
1271
|
+
content: chunkText,
|
|
1272
|
+
embedding
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
this.saveIndex();
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Remove a file from index
|
|
1279
|
+
*/
|
|
1280
|
+
async removeFile(filePath) {
|
|
1281
|
+
this.loadIndex();
|
|
1282
|
+
if (!this.index) return;
|
|
1283
|
+
const initialCount = this.index.chunks.length;
|
|
1284
|
+
this.index.chunks = this.index.chunks.filter((c) => c.filePath !== filePath);
|
|
1285
|
+
if (this.index.chunks.length !== initialCount) {
|
|
1286
|
+
logger.info(`RAG: Removed file ${filePath} from index (${initialCount - this.index.chunks.length} chunks removed)`);
|
|
1287
|
+
this.saveIndex();
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Search the index
|
|
1292
|
+
*/
|
|
1293
|
+
async search(query, limit = 5) {
|
|
1294
|
+
this.loadIndex();
|
|
1295
|
+
if (!this.index || this.index.chunks.length === 0) {
|
|
1296
|
+
logger.warn("RAG: Search called on empty index");
|
|
1297
|
+
return [];
|
|
1298
|
+
}
|
|
1299
|
+
logger.info(`RAG: Searching for "${query}" (limit: ${limit})`);
|
|
1300
|
+
const queryEmbedding = await this.generateEmbedding(query);
|
|
1301
|
+
const results = this.index.chunks.map((chunk) => {
|
|
1302
|
+
const score = this.cosineSimilarity(queryEmbedding, chunk.embedding);
|
|
1303
|
+
return { ...chunk, score };
|
|
1304
|
+
});
|
|
1305
|
+
results.sort((a, b) => b.score - a.score);
|
|
1306
|
+
const topResults = results.slice(0, limit);
|
|
1307
|
+
logger.info(`RAG: Search returned ${topResults.length} matches. Top score: ${topResults[0]?.score.toFixed(4)}`);
|
|
1308
|
+
return topResults;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Simple cosine similarity
|
|
1312
|
+
*/
|
|
1313
|
+
cosineSimilarity(a, b) {
|
|
1314
|
+
let dotProduct = 0;
|
|
1315
|
+
let normA = 0;
|
|
1316
|
+
let normB = 0;
|
|
1317
|
+
for (let i = 0; i < a.length; i++) {
|
|
1318
|
+
dotProduct += a[i] * b[i];
|
|
1319
|
+
normA += a[i] * a[i];
|
|
1320
|
+
normB += b[i] * b[i];
|
|
1321
|
+
}
|
|
1322
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Basic content chunker
|
|
1326
|
+
*/
|
|
1327
|
+
chunkContent(content, maxChunkSize = 1e3, overlap = 100) {
|
|
1328
|
+
const chunks = [];
|
|
1329
|
+
let start = 0;
|
|
1330
|
+
while (start < content.length) {
|
|
1331
|
+
let end = start + maxChunkSize;
|
|
1332
|
+
if (end >= content.length) {
|
|
1333
|
+
end = content.length;
|
|
1334
|
+
} else {
|
|
1335
|
+
const lastNewline = content.lastIndexOf("\n", end);
|
|
1336
|
+
if (lastNewline > start + maxChunkSize / 2) {
|
|
1337
|
+
end = lastNewline;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
const chunk = content.substring(start, end).trim();
|
|
1341
|
+
if (chunk.length > 50) {
|
|
1342
|
+
chunks.push(chunk);
|
|
1343
|
+
}
|
|
1344
|
+
if (end === content.length) break;
|
|
1345
|
+
start = end - overlap;
|
|
1346
|
+
}
|
|
1347
|
+
return chunks;
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
// src/mcp/resources.ts
|
|
1354
|
+
import * as fs10 from "fs";
|
|
1355
|
+
import * as path11 from "path";
|
|
1134
1356
|
function getExposedProjects() {
|
|
1135
1357
|
const config = loadMCPConfig();
|
|
1136
1358
|
const allProjects = scanForProjects();
|
|
@@ -1138,12 +1360,12 @@ function getExposedProjects() {
|
|
|
1138
1360
|
const activeProject = detectActiveProject(globalProjects);
|
|
1139
1361
|
let linkedProjects = [];
|
|
1140
1362
|
if (activeProject) {
|
|
1141
|
-
const localConfigPath =
|
|
1363
|
+
const localConfigPath = path11.join(activeProject.dataPath, "config.yaml");
|
|
1142
1364
|
let cfgContent = null;
|
|
1143
|
-
if (
|
|
1144
|
-
cfgContent =
|
|
1145
|
-
} else if (
|
|
1146
|
-
cfgContent =
|
|
1365
|
+
if (fs10.existsSync(path11.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
|
|
1366
|
+
cfgContent = fs10.readFileSync(path11.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
|
|
1367
|
+
} else if (fs10.existsSync(path11.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
|
|
1368
|
+
cfgContent = fs10.readFileSync(path11.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
|
|
1147
1369
|
}
|
|
1148
1370
|
if (cfgContent) {
|
|
1149
1371
|
if (cfgContent.includes("linked_projects:")) {
|
|
@@ -1203,11 +1425,11 @@ function getProjectContext(projectName) {
|
|
|
1203
1425
|
if (!project.knowledgePath) {
|
|
1204
1426
|
return null;
|
|
1205
1427
|
}
|
|
1206
|
-
const contextPath =
|
|
1207
|
-
if (!
|
|
1428
|
+
const contextPath = path11.join(project.knowledgePath, "project-context.md");
|
|
1429
|
+
if (!fs10.existsSync(contextPath)) {
|
|
1208
1430
|
return null;
|
|
1209
1431
|
}
|
|
1210
|
-
return
|
|
1432
|
+
return fs10.readFileSync(contextPath, "utf-8");
|
|
1211
1433
|
}
|
|
1212
1434
|
function getProjectTasks(projectName) {
|
|
1213
1435
|
const config = loadMCPConfig();
|
|
@@ -1220,18 +1442,18 @@ function getProjectTasks(projectName) {
|
|
|
1220
1442
|
if (!permissions.tasks) {
|
|
1221
1443
|
return [];
|
|
1222
1444
|
}
|
|
1223
|
-
if (!project.tasksPath || !
|
|
1445
|
+
if (!project.tasksPath || !fs10.existsSync(project.tasksPath)) {
|
|
1224
1446
|
return [];
|
|
1225
1447
|
}
|
|
1226
1448
|
const tasks = [];
|
|
1227
1449
|
try {
|
|
1228
|
-
const taskDirs =
|
|
1450
|
+
const taskDirs = fs10.readdirSync(project.tasksPath, { withFileTypes: true });
|
|
1229
1451
|
for (const dir of taskDirs) {
|
|
1230
1452
|
if (!dir.isDirectory()) continue;
|
|
1231
|
-
const metaPath =
|
|
1232
|
-
if (
|
|
1453
|
+
const metaPath = path11.join(project.tasksPath, dir.name, "meta.json");
|
|
1454
|
+
if (fs10.existsSync(metaPath)) {
|
|
1233
1455
|
try {
|
|
1234
|
-
const meta = JSON.parse(
|
|
1456
|
+
const meta = JSON.parse(fs10.readFileSync(metaPath, "utf-8"));
|
|
1235
1457
|
tasks.push(meta);
|
|
1236
1458
|
} catch {
|
|
1237
1459
|
}
|
|
@@ -1241,7 +1463,7 @@ function getProjectTasks(projectName) {
|
|
|
1241
1463
|
}
|
|
1242
1464
|
return tasks;
|
|
1243
1465
|
}
|
|
1244
|
-
function searchKnowledge(query) {
|
|
1466
|
+
async function searchKnowledge(query) {
|
|
1245
1467
|
const config = loadMCPConfig();
|
|
1246
1468
|
const projects = getExposedProjects();
|
|
1247
1469
|
const results = [];
|
|
@@ -1249,12 +1471,34 @@ function searchKnowledge(query) {
|
|
|
1249
1471
|
for (const project of projects) {
|
|
1250
1472
|
const permissions = getProjectPermissions(config, project.name, project.dataPath);
|
|
1251
1473
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
1474
|
+
const projConfig = config.projects.find(
|
|
1475
|
+
(p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
|
|
1476
|
+
);
|
|
1477
|
+
const useRAG = projConfig?.semanticSearch?.enabled;
|
|
1478
|
+
if (useRAG) {
|
|
1479
|
+
try {
|
|
1480
|
+
const indexPath = path11.join(project.knowledgePath, "embeddings.json");
|
|
1481
|
+
const rag = new RAGService(indexPath, projConfig?.semanticSearch?.model);
|
|
1482
|
+
const ragResults = await rag.search(query, 5);
|
|
1483
|
+
for (const r of ragResults) {
|
|
1484
|
+
results.push({
|
|
1485
|
+
project: project.name,
|
|
1486
|
+
file: path11.relative(project.knowledgePath, r.filePath),
|
|
1487
|
+
matches: [r.content],
|
|
1488
|
+
// The chunk content is the match
|
|
1489
|
+
score: r.score
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
} catch (e) {
|
|
1493
|
+
}
|
|
1494
|
+
continue;
|
|
1495
|
+
}
|
|
1252
1496
|
try {
|
|
1253
|
-
const files =
|
|
1497
|
+
const files = fs10.readdirSync(project.knowledgePath);
|
|
1254
1498
|
for (const file of files) {
|
|
1255
1499
|
if (!file.endsWith(".md")) continue;
|
|
1256
|
-
const filePath =
|
|
1257
|
-
const content =
|
|
1500
|
+
const filePath = path11.join(project.knowledgePath, file);
|
|
1501
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1258
1502
|
const lines = content.split("\n");
|
|
1259
1503
|
const matches = [];
|
|
1260
1504
|
for (const line of lines) {
|
|
@@ -1276,11 +1520,44 @@ function searchKnowledge(query) {
|
|
|
1276
1520
|
}
|
|
1277
1521
|
return results;
|
|
1278
1522
|
}
|
|
1523
|
+
async function indexKnowledge(projectName, force = false) {
|
|
1524
|
+
const config = loadMCPConfig();
|
|
1525
|
+
const projects = getExposedProjects();
|
|
1526
|
+
const project = projects.find((p) => p.name === projectName || p.path && p.path === projectName);
|
|
1527
|
+
if (!project) {
|
|
1528
|
+
return { success: false, message: `Project '${projectName}' not found`, filesIndexed: 0 };
|
|
1529
|
+
}
|
|
1530
|
+
const projConfig = config.projects.find(
|
|
1531
|
+
(p) => p.path && p.path === project.dataPath || !p.path && p.name === project.name
|
|
1532
|
+
);
|
|
1533
|
+
if (!projConfig?.semanticSearch?.enabled) {
|
|
1534
|
+
return { success: false, message: "Semantic Search is not enabled for this project", filesIndexed: 0 };
|
|
1535
|
+
}
|
|
1536
|
+
if (!project.knowledgePath || !fs10.existsSync(project.knowledgePath)) {
|
|
1537
|
+
return { success: false, message: "No knowledge directory found", filesIndexed: 0 };
|
|
1538
|
+
}
|
|
1539
|
+
try {
|
|
1540
|
+
const indexPath = path11.join(project.knowledgePath, "embeddings.json");
|
|
1541
|
+
const rag = new RAGService(indexPath, projConfig.semanticSearch.model);
|
|
1542
|
+
const files = fs10.readdirSync(project.knowledgePath).filter((f) => f.endsWith(".md"));
|
|
1543
|
+
let count = 0;
|
|
1544
|
+
for (const file of files) {
|
|
1545
|
+
const filePath = path11.join(project.knowledgePath, file);
|
|
1546
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
1547
|
+
await rag.indexFile(path11.join(project.knowledgePath, file), content);
|
|
1548
|
+
count++;
|
|
1549
|
+
}
|
|
1550
|
+
return { success: true, message: `Successfully indexed ${count} files`, filesIndexed: count };
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
return { success: false, message: `Indexing failed: ${error}`, filesIndexed: 0 };
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1279
1555
|
var init_resources = __esm({
|
|
1280
1556
|
"src/mcp/resources.ts"() {
|
|
1281
1557
|
"use strict";
|
|
1282
1558
|
init_config();
|
|
1283
1559
|
init_detection();
|
|
1560
|
+
init_rag();
|
|
1284
1561
|
}
|
|
1285
1562
|
});
|
|
1286
1563
|
|
|
@@ -1429,6 +1706,18 @@ function registerToolHandlers(server) {
|
|
|
1429
1706
|
required: ["query"]
|
|
1430
1707
|
}
|
|
1431
1708
|
},
|
|
1709
|
+
{
|
|
1710
|
+
name: "index_knowledge",
|
|
1711
|
+
description: "Update the semantic search index for a specific project",
|
|
1712
|
+
inputSchema: {
|
|
1713
|
+
type: "object",
|
|
1714
|
+
properties: {
|
|
1715
|
+
project: { type: "string", description: "Name of the project to index" },
|
|
1716
|
+
force: { type: "boolean", description: "Force re-indexing of all files" }
|
|
1717
|
+
},
|
|
1718
|
+
required: ["project"]
|
|
1719
|
+
}
|
|
1720
|
+
},
|
|
1432
1721
|
{
|
|
1433
1722
|
name: "list_projects",
|
|
1434
1723
|
description: "List all projects exposed via MCP",
|
|
@@ -1477,9 +1766,14 @@ function registerToolHandlers(server) {
|
|
|
1477
1766
|
try {
|
|
1478
1767
|
switch (name) {
|
|
1479
1768
|
case "search_knowledge": {
|
|
1480
|
-
const results = searchKnowledge(args.query);
|
|
1769
|
+
const results = await searchKnowledge(args.query);
|
|
1481
1770
|
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
1482
1771
|
}
|
|
1772
|
+
case "index_knowledge": {
|
|
1773
|
+
const params = args;
|
|
1774
|
+
const result = await indexKnowledge(params.project, params.force);
|
|
1775
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1776
|
+
}
|
|
1483
1777
|
case "list_projects": {
|
|
1484
1778
|
const projects = getExposedProjects();
|
|
1485
1779
|
return {
|
|
@@ -1752,8 +2046,8 @@ var init_server = __esm({
|
|
|
1752
2046
|
});
|
|
1753
2047
|
|
|
1754
2048
|
// src/mcp/install.ts
|
|
1755
|
-
import * as
|
|
1756
|
-
import * as
|
|
2049
|
+
import * as fs11 from "fs";
|
|
2050
|
+
import * as path12 from "path";
|
|
1757
2051
|
import * as os from "os";
|
|
1758
2052
|
function checkInstallStatus(workspacePath) {
|
|
1759
2053
|
return {
|
|
@@ -1764,37 +2058,37 @@ function checkInstallStatus(workspacePath) {
|
|
|
1764
2058
|
};
|
|
1765
2059
|
}
|
|
1766
2060
|
function checkAntigravityConfig() {
|
|
1767
|
-
if (!
|
|
2061
|
+
if (!fs11.existsSync(ANTIGRAVITY_CONFIG)) return false;
|
|
1768
2062
|
try {
|
|
1769
|
-
const content = JSON.parse(
|
|
2063
|
+
const content = JSON.parse(fs11.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
1770
2064
|
return !!content.mcpServers?.["rrce"];
|
|
1771
2065
|
} catch {
|
|
1772
2066
|
return false;
|
|
1773
2067
|
}
|
|
1774
2068
|
}
|
|
1775
2069
|
function checkClaudeConfig() {
|
|
1776
|
-
if (!
|
|
2070
|
+
if (!fs11.existsSync(CLAUDE_CONFIG)) return false;
|
|
1777
2071
|
try {
|
|
1778
|
-
const content = JSON.parse(
|
|
2072
|
+
const content = JSON.parse(fs11.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
1779
2073
|
return !!content.mcpServers?.["rrce"];
|
|
1780
2074
|
} catch {
|
|
1781
2075
|
return false;
|
|
1782
2076
|
}
|
|
1783
2077
|
}
|
|
1784
2078
|
function checkVSCodeGlobalConfig() {
|
|
1785
|
-
if (!
|
|
2079
|
+
if (!fs11.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
|
|
1786
2080
|
try {
|
|
1787
|
-
const content = JSON.parse(
|
|
2081
|
+
const content = JSON.parse(fs11.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
1788
2082
|
return !!content["mcp.servers"]?.["rrce"];
|
|
1789
2083
|
} catch {
|
|
1790
2084
|
return false;
|
|
1791
2085
|
}
|
|
1792
2086
|
}
|
|
1793
2087
|
function checkVSCodeWorkspaceConfig(workspacePath) {
|
|
1794
|
-
const configPath =
|
|
1795
|
-
if (!
|
|
2088
|
+
const configPath = path12.join(workspacePath, ".vscode", "mcp.json");
|
|
2089
|
+
if (!fs11.existsSync(configPath)) return false;
|
|
1796
2090
|
try {
|
|
1797
|
-
const content = JSON.parse(
|
|
2091
|
+
const content = JSON.parse(fs11.readFileSync(configPath, "utf-8"));
|
|
1798
2092
|
return !!content.servers?.["rrce"];
|
|
1799
2093
|
} catch {
|
|
1800
2094
|
return false;
|
|
@@ -1819,14 +2113,14 @@ function installToConfig(target, workspacePath) {
|
|
|
1819
2113
|
}
|
|
1820
2114
|
}
|
|
1821
2115
|
function installToAntigravity() {
|
|
1822
|
-
const dir =
|
|
1823
|
-
if (!
|
|
1824
|
-
|
|
2116
|
+
const dir = path12.dirname(ANTIGRAVITY_CONFIG);
|
|
2117
|
+
if (!fs11.existsSync(dir)) {
|
|
2118
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
1825
2119
|
}
|
|
1826
2120
|
let config = { mcpServers: {} };
|
|
1827
|
-
if (
|
|
2121
|
+
if (fs11.existsSync(ANTIGRAVITY_CONFIG)) {
|
|
1828
2122
|
try {
|
|
1829
|
-
config = JSON.parse(
|
|
2123
|
+
config = JSON.parse(fs11.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
|
|
1830
2124
|
} catch {
|
|
1831
2125
|
}
|
|
1832
2126
|
}
|
|
@@ -1836,21 +2130,21 @@ function installToAntigravity() {
|
|
|
1836
2130
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1837
2131
|
};
|
|
1838
2132
|
try {
|
|
1839
|
-
|
|
2133
|
+
fs11.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
|
|
1840
2134
|
return true;
|
|
1841
2135
|
} catch {
|
|
1842
2136
|
return false;
|
|
1843
2137
|
}
|
|
1844
2138
|
}
|
|
1845
2139
|
function installToClaude() {
|
|
1846
|
-
const dir =
|
|
1847
|
-
if (!
|
|
1848
|
-
|
|
2140
|
+
const dir = path12.dirname(CLAUDE_CONFIG);
|
|
2141
|
+
if (!fs11.existsSync(dir)) {
|
|
2142
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
1849
2143
|
}
|
|
1850
2144
|
let config = { mcpServers: {} };
|
|
1851
|
-
if (
|
|
2145
|
+
if (fs11.existsSync(CLAUDE_CONFIG)) {
|
|
1852
2146
|
try {
|
|
1853
|
-
config = JSON.parse(
|
|
2147
|
+
config = JSON.parse(fs11.readFileSync(CLAUDE_CONFIG, "utf-8"));
|
|
1854
2148
|
} catch {
|
|
1855
2149
|
}
|
|
1856
2150
|
}
|
|
@@ -1860,21 +2154,21 @@ function installToClaude() {
|
|
|
1860
2154
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1861
2155
|
};
|
|
1862
2156
|
try {
|
|
1863
|
-
|
|
2157
|
+
fs11.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
|
|
1864
2158
|
return true;
|
|
1865
2159
|
} catch {
|
|
1866
2160
|
return false;
|
|
1867
2161
|
}
|
|
1868
2162
|
}
|
|
1869
2163
|
function installToVSCodeGlobal() {
|
|
1870
|
-
const dir =
|
|
1871
|
-
if (!
|
|
1872
|
-
|
|
2164
|
+
const dir = path12.dirname(VSCODE_GLOBAL_CONFIG);
|
|
2165
|
+
if (!fs11.existsSync(dir)) {
|
|
2166
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
1873
2167
|
}
|
|
1874
2168
|
let settings = {};
|
|
1875
|
-
if (
|
|
2169
|
+
if (fs11.existsSync(VSCODE_GLOBAL_CONFIG)) {
|
|
1876
2170
|
try {
|
|
1877
|
-
settings = JSON.parse(
|
|
2171
|
+
settings = JSON.parse(fs11.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
|
|
1878
2172
|
} catch {
|
|
1879
2173
|
}
|
|
1880
2174
|
}
|
|
@@ -1884,22 +2178,22 @@ function installToVSCodeGlobal() {
|
|
|
1884
2178
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1885
2179
|
};
|
|
1886
2180
|
try {
|
|
1887
|
-
|
|
2181
|
+
fs11.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
|
|
1888
2182
|
return true;
|
|
1889
2183
|
} catch {
|
|
1890
2184
|
return false;
|
|
1891
2185
|
}
|
|
1892
2186
|
}
|
|
1893
2187
|
function installToVSCodeWorkspace(workspacePath) {
|
|
1894
|
-
const vscodeDir =
|
|
1895
|
-
const configPath =
|
|
1896
|
-
if (!
|
|
1897
|
-
|
|
2188
|
+
const vscodeDir = path12.join(workspacePath, ".vscode");
|
|
2189
|
+
const configPath = path12.join(vscodeDir, "mcp.json");
|
|
2190
|
+
if (!fs11.existsSync(vscodeDir)) {
|
|
2191
|
+
fs11.mkdirSync(vscodeDir, { recursive: true });
|
|
1898
2192
|
}
|
|
1899
2193
|
let config = { servers: {} };
|
|
1900
|
-
if (
|
|
2194
|
+
if (fs11.existsSync(configPath)) {
|
|
1901
2195
|
try {
|
|
1902
|
-
config = JSON.parse(
|
|
2196
|
+
config = JSON.parse(fs11.readFileSync(configPath, "utf-8"));
|
|
1903
2197
|
} catch {
|
|
1904
2198
|
}
|
|
1905
2199
|
}
|
|
@@ -1909,7 +2203,7 @@ function installToVSCodeWorkspace(workspacePath) {
|
|
|
1909
2203
|
args: ["-y", "rrce-workflow", "mcp", "start"]
|
|
1910
2204
|
};
|
|
1911
2205
|
try {
|
|
1912
|
-
|
|
2206
|
+
fs11.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1913
2207
|
return true;
|
|
1914
2208
|
} catch {
|
|
1915
2209
|
return false;
|
|
@@ -1933,14 +2227,14 @@ var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG;
|
|
|
1933
2227
|
var init_install = __esm({
|
|
1934
2228
|
"src/mcp/install.ts"() {
|
|
1935
2229
|
"use strict";
|
|
1936
|
-
ANTIGRAVITY_CONFIG =
|
|
1937
|
-
CLAUDE_CONFIG =
|
|
1938
|
-
VSCODE_GLOBAL_CONFIG =
|
|
2230
|
+
ANTIGRAVITY_CONFIG = path12.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
|
|
2231
|
+
CLAUDE_CONFIG = path12.join(os.homedir(), ".config/claude/claude_desktop_config.json");
|
|
2232
|
+
VSCODE_GLOBAL_CONFIG = path12.join(os.homedir(), ".config/Code/User/settings.json");
|
|
1939
2233
|
}
|
|
1940
2234
|
});
|
|
1941
2235
|
|
|
1942
2236
|
// src/mcp/commands/configure.ts
|
|
1943
|
-
import { spinner, note as note2, multiselect, isCancel as isCancel2 } from "@clack/prompts";
|
|
2237
|
+
import { spinner, note as note2, multiselect, isCancel as isCancel2, confirm } from "@clack/prompts";
|
|
1944
2238
|
import pc3 from "picocolors";
|
|
1945
2239
|
async function handleConfigure() {
|
|
1946
2240
|
const s = spinner();
|
|
@@ -1982,9 +2276,30 @@ async function handleConfigure() {
|
|
|
1982
2276
|
}
|
|
1983
2277
|
const selectedPaths = selected;
|
|
1984
2278
|
logger.info("Configure: User selected projects by path", selectedPaths);
|
|
2279
|
+
let enableSemanticSearch = false;
|
|
2280
|
+
if (selectedPaths.length > 0) {
|
|
2281
|
+
const shouldEnable = await confirm({
|
|
2282
|
+
message: "Enable Semantic Search (Local Mini RAG)?",
|
|
2283
|
+
initialValue: false
|
|
2284
|
+
});
|
|
2285
|
+
if (isCancel2(shouldEnable)) return;
|
|
2286
|
+
enableSemanticSearch = shouldEnable;
|
|
2287
|
+
if (enableSemanticSearch) {
|
|
2288
|
+
note2(
|
|
2289
|
+
`This enables "search_knowledge" tool for agents.
|
|
2290
|
+
First use will download a ~100MB embedding model (all-MiniLM-L6-v2)
|
|
2291
|
+
to your local device (one-time).`,
|
|
2292
|
+
"Semantic Search Enabled"
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
1985
2296
|
for (const project of projects) {
|
|
1986
2297
|
const shouldExpose = selectedPaths.includes(project.dataPath);
|
|
1987
|
-
|
|
2298
|
+
let semanticConfig = void 0;
|
|
2299
|
+
if (shouldExpose && enableSemanticSearch) {
|
|
2300
|
+
semanticConfig = { enabled: true };
|
|
2301
|
+
}
|
|
2302
|
+
setProjectConfig(config, project.name, shouldExpose, void 0, project.dataPath, semanticConfig);
|
|
1988
2303
|
}
|
|
1989
2304
|
saveMCPConfig(config);
|
|
1990
2305
|
logger.info("Configure: Config saved", config);
|
|
@@ -1999,8 +2314,8 @@ Hidden projects: ${projects.length - exposedCount}`,
|
|
|
1999
2314
|
}
|
|
2000
2315
|
async function handleConfigureGlobalPath() {
|
|
2001
2316
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
2002
|
-
const
|
|
2003
|
-
const
|
|
2317
|
+
const fs18 = await import("fs");
|
|
2318
|
+
const path17 = await import("path");
|
|
2004
2319
|
note2(
|
|
2005
2320
|
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
2006
2321
|
and coordinate across projects.
|
|
@@ -2014,8 +2329,8 @@ locally in each project. MCP needs a central location.`,
|
|
|
2014
2329
|
return false;
|
|
2015
2330
|
}
|
|
2016
2331
|
try {
|
|
2017
|
-
if (!
|
|
2018
|
-
|
|
2332
|
+
if (!fs18.existsSync(resolvedPath)) {
|
|
2333
|
+
fs18.mkdirSync(resolvedPath, { recursive: true });
|
|
2019
2334
|
}
|
|
2020
2335
|
const config = loadMCPConfig();
|
|
2021
2336
|
saveMCPConfig(config);
|
|
@@ -2023,7 +2338,7 @@ locally in each project. MCP needs a central location.`,
|
|
|
2023
2338
|
`${pc3.green("\u2713")} Global path configured: ${pc3.cyan(resolvedPath)}
|
|
2024
2339
|
|
|
2025
2340
|
MCP config will be stored at:
|
|
2026
|
-
${
|
|
2341
|
+
${path17.join(resolvedPath, "mcp.yaml")}`,
|
|
2027
2342
|
"Configuration Saved"
|
|
2028
2343
|
);
|
|
2029
2344
|
return true;
|
|
@@ -2500,7 +2815,7 @@ __export(App_exports, {
|
|
|
2500
2815
|
});
|
|
2501
2816
|
import { useState as useState4, useEffect as useEffect4 } from "react";
|
|
2502
2817
|
import { Box as Box10, useInput as useInput3, useApp } from "ink";
|
|
2503
|
-
import
|
|
2818
|
+
import fs12 from "fs";
|
|
2504
2819
|
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2505
2820
|
var TABS, App;
|
|
2506
2821
|
var init_App = __esm({
|
|
@@ -2569,18 +2884,18 @@ var init_App = __esm({
|
|
|
2569
2884
|
useEffect4(() => {
|
|
2570
2885
|
const logPath = getLogFilePath();
|
|
2571
2886
|
let lastSize = 0;
|
|
2572
|
-
if (
|
|
2573
|
-
const stats =
|
|
2887
|
+
if (fs12.existsSync(logPath)) {
|
|
2888
|
+
const stats = fs12.statSync(logPath);
|
|
2574
2889
|
lastSize = stats.size;
|
|
2575
2890
|
}
|
|
2576
2891
|
const interval = setInterval(() => {
|
|
2577
|
-
if (
|
|
2578
|
-
const stats =
|
|
2892
|
+
if (fs12.existsSync(logPath)) {
|
|
2893
|
+
const stats = fs12.statSync(logPath);
|
|
2579
2894
|
if (stats.size > lastSize) {
|
|
2580
2895
|
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
2581
|
-
const fd =
|
|
2582
|
-
|
|
2583
|
-
|
|
2896
|
+
const fd = fs12.openSync(logPath, "r");
|
|
2897
|
+
fs12.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
2898
|
+
fs12.closeSync(fd);
|
|
2584
2899
|
const newContent = buffer.toString("utf-8");
|
|
2585
2900
|
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
2586
2901
|
setLogs((prev) => {
|
|
@@ -2638,7 +2953,7 @@ var init_App = __esm({
|
|
|
2638
2953
|
});
|
|
2639
2954
|
|
|
2640
2955
|
// src/mcp/commands/start.ts
|
|
2641
|
-
import { confirm, isCancel as isCancel4, text } from "@clack/prompts";
|
|
2956
|
+
import { confirm as confirm2, isCancel as isCancel4, text } from "@clack/prompts";
|
|
2642
2957
|
async function handleStartServer() {
|
|
2643
2958
|
const React11 = await import("react");
|
|
2644
2959
|
const { render } = await import("ink");
|
|
@@ -2652,7 +2967,7 @@ async function handleStartServer() {
|
|
|
2652
2967
|
return cfg?.expose ?? config.defaults.includeNew;
|
|
2653
2968
|
});
|
|
2654
2969
|
if (exposedProjects.length === 0) {
|
|
2655
|
-
const shouldConfig = await
|
|
2970
|
+
const shouldConfig = await confirm2({
|
|
2656
2971
|
message: "No projects are currently exposed. Configure now?",
|
|
2657
2972
|
initialValue: true
|
|
2658
2973
|
});
|
|
@@ -2813,7 +3128,7 @@ __export(mcp_exports, {
|
|
|
2813
3128
|
handleStartServer: () => handleStartServer,
|
|
2814
3129
|
runMCP: () => runMCP
|
|
2815
3130
|
});
|
|
2816
|
-
import { intro, outro, confirm as
|
|
3131
|
+
import { intro, outro, confirm as confirm3, note as note6, isCancel as isCancel5 } from "@clack/prompts";
|
|
2817
3132
|
import pc7 from "picocolors";
|
|
2818
3133
|
async function runMCP(subcommand2) {
|
|
2819
3134
|
if (subcommand2) {
|
|
@@ -2861,13 +3176,13 @@ async function runMCP(subcommand2) {
|
|
|
2861
3176
|
Allow AI assistants to access your project context.`,
|
|
2862
3177
|
"Getting Started"
|
|
2863
3178
|
);
|
|
2864
|
-
const shouldInstall = await
|
|
3179
|
+
const shouldInstall = await confirm3({
|
|
2865
3180
|
message: "Install MCP server integrations now?",
|
|
2866
3181
|
initialValue: true
|
|
2867
3182
|
});
|
|
2868
3183
|
if (shouldInstall && !isCancel5(shouldInstall)) {
|
|
2869
3184
|
await runInstallWizard(workspacePath);
|
|
2870
|
-
const shouldStart = await
|
|
3185
|
+
const shouldStart = await confirm3({
|
|
2871
3186
|
message: "Start the MCP Dashboard?",
|
|
2872
3187
|
initialValue: true
|
|
2873
3188
|
});
|
|
@@ -2912,10 +3227,10 @@ var init_mcp = __esm({
|
|
|
2912
3227
|
});
|
|
2913
3228
|
|
|
2914
3229
|
// src/commands/wizard/setup-flow.ts
|
|
2915
|
-
import { group, select as select2, multiselect as multiselect3, confirm as
|
|
3230
|
+
import { group, select as select2, multiselect as multiselect3, confirm as confirm4, spinner as spinner3, note as note7, outro as outro2, cancel as cancel2, isCancel as isCancel6 } from "@clack/prompts";
|
|
2916
3231
|
import pc8 from "picocolors";
|
|
2917
|
-
import * as
|
|
2918
|
-
import * as
|
|
3232
|
+
import * as fs13 from "fs";
|
|
3233
|
+
import * as path13 from "path";
|
|
2919
3234
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
2920
3235
|
const s = spinner3();
|
|
2921
3236
|
const config = await group(
|
|
@@ -2953,15 +3268,15 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
2953
3268
|
required: false
|
|
2954
3269
|
});
|
|
2955
3270
|
},
|
|
2956
|
-
addToGitignore: () =>
|
|
3271
|
+
addToGitignore: () => confirm4({
|
|
2957
3272
|
message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
|
|
2958
3273
|
initialValue: true
|
|
2959
3274
|
}),
|
|
2960
|
-
confirm: () =>
|
|
3275
|
+
confirm: () => confirm4({
|
|
2961
3276
|
message: "Create configuration?",
|
|
2962
3277
|
initialValue: true
|
|
2963
3278
|
}),
|
|
2964
|
-
exposeToMCP: () =>
|
|
3279
|
+
exposeToMCP: () => confirm4({
|
|
2965
3280
|
message: "Expose this project to MCP (AI Agent) server?",
|
|
2966
3281
|
initialValue: true
|
|
2967
3282
|
})
|
|
@@ -3030,7 +3345,7 @@ async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
|
3030
3345
|
outro2(pc8.green(`\u2713 Setup complete! Your agents are ready to use.`));
|
|
3031
3346
|
}
|
|
3032
3347
|
} else {
|
|
3033
|
-
const shouldConfigureMCP = await
|
|
3348
|
+
const shouldConfigureMCP = await confirm4({
|
|
3034
3349
|
message: "Would you like to configure the MCP server now?",
|
|
3035
3350
|
initialValue: true
|
|
3036
3351
|
});
|
|
@@ -3055,14 +3370,14 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
3055
3370
|
const dataPaths = getDataPaths(config.storageMode, workspaceName, workspacePath, config.globalPath);
|
|
3056
3371
|
for (const dataPath of dataPaths) {
|
|
3057
3372
|
ensureDir(dataPath);
|
|
3058
|
-
ensureDir(
|
|
3059
|
-
ensureDir(
|
|
3060
|
-
ensureDir(
|
|
3061
|
-
ensureDir(
|
|
3373
|
+
ensureDir(path13.join(dataPath, "knowledge"));
|
|
3374
|
+
ensureDir(path13.join(dataPath, "refs"));
|
|
3375
|
+
ensureDir(path13.join(dataPath, "tasks"));
|
|
3376
|
+
ensureDir(path13.join(dataPath, "templates"));
|
|
3062
3377
|
}
|
|
3063
3378
|
const agentCoreDir = getAgentCoreDir();
|
|
3064
3379
|
syncMetadataToAll(agentCoreDir, dataPaths);
|
|
3065
|
-
copyDirToAllStoragePaths(
|
|
3380
|
+
copyDirToAllStoragePaths(path13.join(agentCoreDir, "templates"), "templates", dataPaths);
|
|
3066
3381
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
3067
3382
|
if (config.tools.includes("copilot")) {
|
|
3068
3383
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
@@ -3074,8 +3389,8 @@ async function generateConfiguration(config, workspacePath, workspaceName, allPr
|
|
|
3074
3389
|
ensureDir(antigravityPath);
|
|
3075
3390
|
copyPromptsToDir(prompts, antigravityPath, ".md");
|
|
3076
3391
|
}
|
|
3077
|
-
const workspaceConfigPath =
|
|
3078
|
-
ensureDir(
|
|
3392
|
+
const workspaceConfigPath = path13.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
3393
|
+
ensureDir(path13.dirname(workspaceConfigPath));
|
|
3079
3394
|
let configContent = `# RRCE-Workflow Configuration
|
|
3080
3395
|
version: 1
|
|
3081
3396
|
|
|
@@ -3103,7 +3418,7 @@ linked_projects:
|
|
|
3103
3418
|
`;
|
|
3104
3419
|
});
|
|
3105
3420
|
}
|
|
3106
|
-
|
|
3421
|
+
fs13.writeFileSync(workspaceConfigPath, configContent);
|
|
3107
3422
|
if (config.addToGitignore) {
|
|
3108
3423
|
updateGitignore(workspacePath, config.storageMode, config.tools);
|
|
3109
3424
|
}
|
|
@@ -3132,8 +3447,8 @@ linked_projects:
|
|
|
3132
3447
|
}
|
|
3133
3448
|
}
|
|
3134
3449
|
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
3135
|
-
const globalPath =
|
|
3136
|
-
const workspacePath =
|
|
3450
|
+
const globalPath = path13.join(customGlobalPath || getDefaultRRCEHome(), "workspaces", workspaceName);
|
|
3451
|
+
const workspacePath = path13.join(workspaceRoot, ".rrce-workflow");
|
|
3137
3452
|
switch (mode) {
|
|
3138
3453
|
case "global":
|
|
3139
3454
|
return [globalPath];
|
|
@@ -3144,7 +3459,7 @@ function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
|
3144
3459
|
}
|
|
3145
3460
|
}
|
|
3146
3461
|
function updateGitignore(workspacePath, storageMode, tools) {
|
|
3147
|
-
const gitignorePath =
|
|
3462
|
+
const gitignorePath = path13.join(workspacePath, ".gitignore");
|
|
3148
3463
|
const entries = [];
|
|
3149
3464
|
if (storageMode === "workspace") {
|
|
3150
3465
|
entries.push(".rrce-workflow/");
|
|
@@ -3160,8 +3475,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
3160
3475
|
}
|
|
3161
3476
|
try {
|
|
3162
3477
|
let content = "";
|
|
3163
|
-
if (
|
|
3164
|
-
content =
|
|
3478
|
+
if (fs13.existsSync(gitignorePath)) {
|
|
3479
|
+
content = fs13.readFileSync(gitignorePath, "utf-8");
|
|
3165
3480
|
}
|
|
3166
3481
|
const lines = content.split("\n").map((line) => line.trim());
|
|
3167
3482
|
const newEntries = [];
|
|
@@ -3186,7 +3501,7 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
3186
3501
|
newContent += "\n# rrce-workflow generated folders (uncomment to ignore)\n";
|
|
3187
3502
|
}
|
|
3188
3503
|
newContent += newEntries.map((e) => `# ${e}`).join("\n") + "\n";
|
|
3189
|
-
|
|
3504
|
+
fs13.writeFileSync(gitignorePath, newContent);
|
|
3190
3505
|
return true;
|
|
3191
3506
|
} catch {
|
|
3192
3507
|
return false;
|
|
@@ -3205,9 +3520,9 @@ var init_setup_flow = __esm({
|
|
|
3205
3520
|
});
|
|
3206
3521
|
|
|
3207
3522
|
// src/commands/wizard/link-flow.ts
|
|
3208
|
-
import { multiselect as multiselect4, spinner as spinner4, note as note8, outro as outro3, cancel as cancel3, isCancel as isCancel7, confirm as
|
|
3523
|
+
import { multiselect as multiselect4, spinner as spinner4, note as note8, outro as outro3, cancel as cancel3, isCancel as isCancel7, confirm as confirm5 } from "@clack/prompts";
|
|
3209
3524
|
import pc9 from "picocolors";
|
|
3210
|
-
import * as
|
|
3525
|
+
import * as fs14 from "fs";
|
|
3211
3526
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
3212
3527
|
const projects = scanForProjects({
|
|
3213
3528
|
excludeWorkspace: workspaceName,
|
|
@@ -3245,7 +3560,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
3245
3560
|
const s = spinner4();
|
|
3246
3561
|
s.start("Linking projects");
|
|
3247
3562
|
const configFilePath = getConfigPath(workspacePath);
|
|
3248
|
-
let configContent =
|
|
3563
|
+
let configContent = fs14.readFileSync(configFilePath, "utf-8");
|
|
3249
3564
|
if (configContent.includes("linked_projects:")) {
|
|
3250
3565
|
const lines = configContent.split("\n");
|
|
3251
3566
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -3272,7 +3587,7 @@ linked_projects:
|
|
|
3272
3587
|
`;
|
|
3273
3588
|
});
|
|
3274
3589
|
}
|
|
3275
|
-
|
|
3590
|
+
fs14.writeFileSync(configFilePath, configContent);
|
|
3276
3591
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
3277
3592
|
s.stop("Projects linked");
|
|
3278
3593
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
@@ -3284,7 +3599,7 @@ linked_projects:
|
|
|
3284
3599
|
];
|
|
3285
3600
|
note8(summary.join("\n"), "Link Summary");
|
|
3286
3601
|
outro3(pc9.green(`\u2713 Projects linked! Open ${pc9.bold(workspaceFile)} in VSCode to access linked data.`));
|
|
3287
|
-
const shouldExpose = await
|
|
3602
|
+
const shouldExpose = await confirm5({
|
|
3288
3603
|
message: "Also expose these linked projects to the MCP server (for Agent access)?",
|
|
3289
3604
|
initialValue: true
|
|
3290
3605
|
});
|
|
@@ -3312,17 +3627,17 @@ var init_link_flow = __esm({
|
|
|
3312
3627
|
});
|
|
3313
3628
|
|
|
3314
3629
|
// src/commands/wizard/sync-flow.ts
|
|
3315
|
-
import { confirm as
|
|
3630
|
+
import { confirm as confirm6, spinner as spinner5, note as note9, outro as outro4, cancel as cancel4, isCancel as isCancel8 } from "@clack/prompts";
|
|
3316
3631
|
import pc10 from "picocolors";
|
|
3317
|
-
import * as
|
|
3318
|
-
import * as
|
|
3632
|
+
import * as fs15 from "fs";
|
|
3633
|
+
import * as path14 from "path";
|
|
3319
3634
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
3320
3635
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
3321
3636
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
3322
|
-
const globalPath =
|
|
3637
|
+
const globalPath = path14.join(customGlobalPath, "workspaces", workspaceName);
|
|
3323
3638
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
3324
3639
|
const existingDirs = subdirs.filter(
|
|
3325
|
-
(dir) =>
|
|
3640
|
+
(dir) => fs15.existsSync(path14.join(localPath, dir))
|
|
3326
3641
|
);
|
|
3327
3642
|
if (existingDirs.length === 0) {
|
|
3328
3643
|
outro4(pc10.yellow("No data found in workspace storage to sync."));
|
|
@@ -3335,7 +3650,7 @@ ${existingDirs.map((d) => ` \u2022 ${d}/`).join("\n")}
|
|
|
3335
3650
|
Destination: ${pc10.cyan(globalPath)}`,
|
|
3336
3651
|
"Sync Preview"
|
|
3337
3652
|
);
|
|
3338
|
-
const shouldSync = await
|
|
3653
|
+
const shouldSync = await confirm6({
|
|
3339
3654
|
message: "Proceed with sync to global storage?",
|
|
3340
3655
|
initialValue: true
|
|
3341
3656
|
});
|
|
@@ -3348,8 +3663,8 @@ Destination: ${pc10.cyan(globalPath)}`,
|
|
|
3348
3663
|
try {
|
|
3349
3664
|
ensureDir(globalPath);
|
|
3350
3665
|
for (const dir of existingDirs) {
|
|
3351
|
-
const srcDir =
|
|
3352
|
-
const destDir =
|
|
3666
|
+
const srcDir = path14.join(localPath, dir);
|
|
3667
|
+
const destDir = path14.join(globalPath, dir);
|
|
3353
3668
|
ensureDir(destDir);
|
|
3354
3669
|
copyDirRecursive(srcDir, destDir);
|
|
3355
3670
|
}
|
|
@@ -3379,10 +3694,10 @@ var init_sync_flow = __esm({
|
|
|
3379
3694
|
});
|
|
3380
3695
|
|
|
3381
3696
|
// src/commands/wizard/update-flow.ts
|
|
3382
|
-
import { confirm as
|
|
3697
|
+
import { confirm as confirm7, spinner as spinner6, note as note10, outro as outro5, cancel as cancel5, isCancel as isCancel9 } from "@clack/prompts";
|
|
3383
3698
|
import pc11 from "picocolors";
|
|
3384
|
-
import * as
|
|
3385
|
-
import * as
|
|
3699
|
+
import * as fs16 from "fs";
|
|
3700
|
+
import * as path15 from "path";
|
|
3386
3701
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
3387
3702
|
const s = spinner6();
|
|
3388
3703
|
s.start("Checking for updates");
|
|
@@ -3402,7 +3717,7 @@ Target locations:
|
|
|
3402
3717
|
${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
3403
3718
|
"Update Preview"
|
|
3404
3719
|
);
|
|
3405
|
-
const shouldUpdate = await
|
|
3720
|
+
const shouldUpdate = await confirm7({
|
|
3406
3721
|
message: "Proceed with update?",
|
|
3407
3722
|
initialValue: true
|
|
3408
3723
|
});
|
|
@@ -3412,10 +3727,10 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
3412
3727
|
}
|
|
3413
3728
|
s.start("Updating from package");
|
|
3414
3729
|
for (const dataPath of dataPaths) {
|
|
3415
|
-
copyDirToAllStoragePaths(
|
|
3730
|
+
copyDirToAllStoragePaths(path15.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
3416
3731
|
}
|
|
3417
3732
|
const configFilePath = getConfigPath(workspacePath);
|
|
3418
|
-
const configContent =
|
|
3733
|
+
const configContent = fs16.readFileSync(configFilePath, "utf-8");
|
|
3419
3734
|
if (configContent.includes("copilot: true")) {
|
|
3420
3735
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
3421
3736
|
ensureDir(copilotPath);
|
|
@@ -3443,8 +3758,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
3443
3758
|
}
|
|
3444
3759
|
}
|
|
3445
3760
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
3446
|
-
const globalPath =
|
|
3447
|
-
const workspacePath =
|
|
3761
|
+
const globalPath = path15.join(customGlobalPath, "workspaces", workspaceName);
|
|
3762
|
+
const workspacePath = path15.join(workspaceRoot, ".rrce-workflow");
|
|
3448
3763
|
switch (mode) {
|
|
3449
3764
|
case "global":
|
|
3450
3765
|
return [globalPath];
|
|
@@ -3470,7 +3785,7 @@ __export(wizard_exports, {
|
|
|
3470
3785
|
});
|
|
3471
3786
|
import { intro as intro2, select as select3, spinner as spinner7, note as note11, outro as outro6, isCancel as isCancel10 } from "@clack/prompts";
|
|
3472
3787
|
import pc12 from "picocolors";
|
|
3473
|
-
import * as
|
|
3788
|
+
import * as fs17 from "fs";
|
|
3474
3789
|
async function runWizard() {
|
|
3475
3790
|
intro2(pc12.cyan(pc12.inverse(" RRCE-Workflow Setup ")));
|
|
3476
3791
|
const s = spinner7();
|
|
@@ -3490,18 +3805,18 @@ Workspace: ${pc12.bold(workspaceName)}`,
|
|
|
3490
3805
|
workspacePath
|
|
3491
3806
|
});
|
|
3492
3807
|
const configFilePath = getConfigPath(workspacePath);
|
|
3493
|
-
const isAlreadyConfigured =
|
|
3808
|
+
const isAlreadyConfigured = fs17.existsSync(configFilePath);
|
|
3494
3809
|
let currentStorageMode = null;
|
|
3495
3810
|
if (isAlreadyConfigured) {
|
|
3496
3811
|
try {
|
|
3497
|
-
const configContent =
|
|
3812
|
+
const configContent = fs17.readFileSync(configFilePath, "utf-8");
|
|
3498
3813
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
3499
3814
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
3500
3815
|
} catch {
|
|
3501
3816
|
}
|
|
3502
3817
|
}
|
|
3503
3818
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
3504
|
-
const hasLocalData =
|
|
3819
|
+
const hasLocalData = fs17.existsSync(localDataPath);
|
|
3505
3820
|
if (isAlreadyConfigured) {
|
|
3506
3821
|
const menuOptions = [];
|
|
3507
3822
|
menuOptions.push({
|
|
@@ -3576,9 +3891,9 @@ init_wizard();
|
|
|
3576
3891
|
init_prompts();
|
|
3577
3892
|
import { intro as intro3, select as select4, note as note12, cancel as cancel7, isCancel as isCancel11, outro as outro7 } from "@clack/prompts";
|
|
3578
3893
|
import pc13 from "picocolors";
|
|
3579
|
-
import * as
|
|
3894
|
+
import * as path16 from "path";
|
|
3580
3895
|
async function runSelector() {
|
|
3581
|
-
const workspaceName =
|
|
3896
|
+
const workspaceName = path16.basename(process.cwd());
|
|
3582
3897
|
intro3(pc13.cyan(pc13.inverse(` RRCE-Workflow | ${workspaceName} `)));
|
|
3583
3898
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
3584
3899
|
if (prompts.length === 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rrce-workflow",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
|
|
5
5
|
"author": "RRCE Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,11 +49,13 @@
|
|
|
49
49
|
"@clack/core": "^0.5.0",
|
|
50
50
|
"@clack/prompts": "^0.11.0",
|
|
51
51
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
52
|
+
"@xenova/transformers": "^2.17.2",
|
|
52
53
|
"gray-matter": "^4.0.3",
|
|
53
54
|
"ink": "^6.6.0",
|
|
54
55
|
"ink-link": "^5.0.0",
|
|
55
56
|
"ink-spinner": "^5.0.0",
|
|
56
57
|
"ink-text-input": "^6.0.0",
|
|
58
|
+
"onnxruntime-node": "^1.23.2",
|
|
57
59
|
"picocolors": "^1.1.1",
|
|
58
60
|
"react": "^19.2.3",
|
|
59
61
|
"zod": "^4.2.1"
|