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
- permissions:
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/resources.ts
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 = path10.join(activeProject.dataPath, "config.yaml");
1363
+ const localConfigPath = path11.join(activeProject.dataPath, "config.yaml");
1142
1364
  let cfgContent = null;
1143
- if (fs9.existsSync(path10.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"))) {
1144
- cfgContent = fs9.readFileSync(path10.join(activeProject.dataPath, ".rrce-workflow", "config.yaml"), "utf-8");
1145
- } else if (fs9.existsSync(path10.join(activeProject.dataPath, ".rrce-workflow.yaml"))) {
1146
- cfgContent = fs9.readFileSync(path10.join(activeProject.dataPath, ".rrce-workflow.yaml"), "utf-8");
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 = path10.join(project.knowledgePath, "project-context.md");
1207
- if (!fs9.existsSync(contextPath)) {
1428
+ const contextPath = path11.join(project.knowledgePath, "project-context.md");
1429
+ if (!fs10.existsSync(contextPath)) {
1208
1430
  return null;
1209
1431
  }
1210
- return fs9.readFileSync(contextPath, "utf-8");
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 || !fs9.existsSync(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 = fs9.readdirSync(project.tasksPath, { withFileTypes: true });
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 = path10.join(project.tasksPath, dir.name, "meta.json");
1232
- if (fs9.existsSync(metaPath)) {
1453
+ const metaPath = path11.join(project.tasksPath, dir.name, "meta.json");
1454
+ if (fs10.existsSync(metaPath)) {
1233
1455
  try {
1234
- const meta = JSON.parse(fs9.readFileSync(metaPath, "utf-8"));
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 = fs9.readdirSync(project.knowledgePath);
1497
+ const files = fs10.readdirSync(project.knowledgePath);
1254
1498
  for (const file of files) {
1255
1499
  if (!file.endsWith(".md")) continue;
1256
- const filePath = path10.join(project.knowledgePath, file);
1257
- const content = fs9.readFileSync(filePath, "utf-8");
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 fs10 from "fs";
1756
- import * as path11 from "path";
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 (!fs10.existsSync(ANTIGRAVITY_CONFIG)) return false;
2061
+ if (!fs11.existsSync(ANTIGRAVITY_CONFIG)) return false;
1768
2062
  try {
1769
- const content = JSON.parse(fs10.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
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 (!fs10.existsSync(CLAUDE_CONFIG)) return false;
2070
+ if (!fs11.existsSync(CLAUDE_CONFIG)) return false;
1777
2071
  try {
1778
- const content = JSON.parse(fs10.readFileSync(CLAUDE_CONFIG, "utf-8"));
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 (!fs10.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
2079
+ if (!fs11.existsSync(VSCODE_GLOBAL_CONFIG)) return false;
1786
2080
  try {
1787
- const content = JSON.parse(fs10.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
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 = path11.join(workspacePath, ".vscode", "mcp.json");
1795
- if (!fs10.existsSync(configPath)) return false;
2088
+ const configPath = path12.join(workspacePath, ".vscode", "mcp.json");
2089
+ if (!fs11.existsSync(configPath)) return false;
1796
2090
  try {
1797
- const content = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
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 = path11.dirname(ANTIGRAVITY_CONFIG);
1823
- if (!fs10.existsSync(dir)) {
1824
- fs10.mkdirSync(dir, { recursive: true });
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 (fs10.existsSync(ANTIGRAVITY_CONFIG)) {
2121
+ if (fs11.existsSync(ANTIGRAVITY_CONFIG)) {
1828
2122
  try {
1829
- config = JSON.parse(fs10.readFileSync(ANTIGRAVITY_CONFIG, "utf-8"));
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
- fs10.writeFileSync(ANTIGRAVITY_CONFIG, JSON.stringify(config, null, 2));
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 = path11.dirname(CLAUDE_CONFIG);
1847
- if (!fs10.existsSync(dir)) {
1848
- fs10.mkdirSync(dir, { recursive: true });
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 (fs10.existsSync(CLAUDE_CONFIG)) {
2145
+ if (fs11.existsSync(CLAUDE_CONFIG)) {
1852
2146
  try {
1853
- config = JSON.parse(fs10.readFileSync(CLAUDE_CONFIG, "utf-8"));
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
- fs10.writeFileSync(CLAUDE_CONFIG, JSON.stringify(config, null, 2));
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 = path11.dirname(VSCODE_GLOBAL_CONFIG);
1871
- if (!fs10.existsSync(dir)) {
1872
- fs10.mkdirSync(dir, { recursive: true });
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 (fs10.existsSync(VSCODE_GLOBAL_CONFIG)) {
2169
+ if (fs11.existsSync(VSCODE_GLOBAL_CONFIG)) {
1876
2170
  try {
1877
- settings = JSON.parse(fs10.readFileSync(VSCODE_GLOBAL_CONFIG, "utf-8"));
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
- fs10.writeFileSync(VSCODE_GLOBAL_CONFIG, JSON.stringify(settings, null, 2));
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 = path11.join(workspacePath, ".vscode");
1895
- const configPath = path11.join(vscodeDir, "mcp.json");
1896
- if (!fs10.existsSync(vscodeDir)) {
1897
- fs10.mkdirSync(vscodeDir, { recursive: true });
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 (fs10.existsSync(configPath)) {
2194
+ if (fs11.existsSync(configPath)) {
1901
2195
  try {
1902
- config = JSON.parse(fs10.readFileSync(configPath, "utf-8"));
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
- fs10.writeFileSync(configPath, JSON.stringify(config, null, 2));
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 = path11.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
1937
- CLAUDE_CONFIG = path11.join(os.homedir(), ".config/claude/claude_desktop_config.json");
1938
- VSCODE_GLOBAL_CONFIG = path11.join(os.homedir(), ".config/Code/User/settings.json");
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
- setProjectConfig(config, project.name, shouldExpose, void 0, project.dataPath);
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 fs17 = await import("fs");
2003
- const path16 = await import("path");
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 (!fs17.existsSync(resolvedPath)) {
2018
- fs17.mkdirSync(resolvedPath, { recursive: true });
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
- ${path16.join(resolvedPath, "mcp.yaml")}`,
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 fs11 from "fs";
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 (fs11.existsSync(logPath)) {
2573
- const stats = fs11.statSync(logPath);
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 (fs11.existsSync(logPath)) {
2578
- const stats = fs11.statSync(logPath);
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 = fs11.openSync(logPath, "r");
2582
- fs11.readSync(fd, buffer, 0, buffer.length, lastSize);
2583
- fs11.closeSync(fd);
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 confirm({
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 confirm2, note as note6, isCancel as isCancel5 } from "@clack/prompts";
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 confirm2({
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 confirm2({
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 confirm3, spinner as spinner3, note as note7, outro as outro2, cancel as cancel2, isCancel as isCancel6 } from "@clack/prompts";
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 fs12 from "fs";
2918
- import * as path12 from "path";
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: () => confirm3({
3271
+ addToGitignore: () => confirm4({
2957
3272
  message: "Add generated folders to .gitignore? (as comments - uncomment if needed)",
2958
3273
  initialValue: true
2959
3274
  }),
2960
- confirm: () => confirm3({
3275
+ confirm: () => confirm4({
2961
3276
  message: "Create configuration?",
2962
3277
  initialValue: true
2963
3278
  }),
2964
- exposeToMCP: () => confirm3({
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 confirm3({
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(path12.join(dataPath, "knowledge"));
3059
- ensureDir(path12.join(dataPath, "refs"));
3060
- ensureDir(path12.join(dataPath, "tasks"));
3061
- ensureDir(path12.join(dataPath, "templates"));
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(path12.join(agentCoreDir, "templates"), "templates", dataPaths);
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 = path12.join(workspacePath, ".rrce-workflow", "config.yaml");
3078
- ensureDir(path12.dirname(workspaceConfigPath));
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
- fs12.writeFileSync(workspaceConfigPath, configContent);
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 = path12.join(customGlobalPath || getDefaultRRCEHome(), "workspaces", workspaceName);
3136
- const workspacePath = path12.join(workspaceRoot, ".rrce-workflow");
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 = path12.join(workspacePath, ".gitignore");
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 (fs12.existsSync(gitignorePath)) {
3164
- content = fs12.readFileSync(gitignorePath, "utf-8");
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
- fs12.writeFileSync(gitignorePath, newContent);
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 confirm4 } from "@clack/prompts";
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 fs13 from "fs";
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 = fs13.readFileSync(configFilePath, "utf-8");
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
- fs13.writeFileSync(configFilePath, configContent);
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 confirm4({
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 confirm5, spinner as spinner5, note as note9, outro as outro4, cancel as cancel4, isCancel as isCancel8 } from "@clack/prompts";
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 fs14 from "fs";
3318
- import * as path13 from "path";
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 = path13.join(customGlobalPath, "workspaces", workspaceName);
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) => fs14.existsSync(path13.join(localPath, 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 confirm5({
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 = path13.join(localPath, dir);
3352
- const destDir = path13.join(globalPath, dir);
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 confirm6, spinner as spinner6, note as note10, outro as outro5, cancel as cancel5, isCancel as isCancel9 } from "@clack/prompts";
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 fs15 from "fs";
3385
- import * as path14 from "path";
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 confirm6({
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(path14.join(agentCoreDir, "templates"), "templates", [dataPath]);
3730
+ copyDirToAllStoragePaths(path15.join(agentCoreDir, "templates"), "templates", [dataPath]);
3416
3731
  }
3417
3732
  const configFilePath = getConfigPath(workspacePath);
3418
- const configContent = fs15.readFileSync(configFilePath, "utf-8");
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 = path14.join(customGlobalPath, "workspaces", workspaceName);
3447
- const workspacePath = path14.join(workspaceRoot, ".rrce-workflow");
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 fs16 from "fs";
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 = fs16.existsSync(configFilePath);
3808
+ const isAlreadyConfigured = fs17.existsSync(configFilePath);
3494
3809
  let currentStorageMode = null;
3495
3810
  if (isAlreadyConfigured) {
3496
3811
  try {
3497
- const configContent = fs16.readFileSync(configFilePath, "utf-8");
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 = fs16.existsSync(localDataPath);
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 path15 from "path";
3894
+ import * as path16 from "path";
3580
3895
  async function runSelector() {
3581
- const workspaceName = path15.basename(process.cwd());
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.43",
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"