rrce-workflow 0.2.91 → 0.2.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -28
- package/dist/index.js +223 -33
- package/docs/architecture.md +281 -159
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/rrce-workflow)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
RRCE-Workflow
|
|
8
|
+
RRCE-Workflow transforms your AI coding assistant (GitHub Copilot, OpenCode, Claude Desktop, Antigravity IDE) into a **context-aware agent** with persistent project knowledge.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
**Key Features:**
|
|
11
|
+
- **Global Knowledge Base**: Centralized context management across all your projects (`~/.rrce-workflow/`).
|
|
12
|
+
- **MCP Hub**: A Model Context Protocol server exposing tools, resources, and prompts to any MCP-compatible client.
|
|
13
|
+
- **Semantic Search (RAG)**: Local, privacy-first vector indexing powered by `@xenova/transformers` for deep codebase understanding.
|
|
14
|
+
- **Structured Agent Pipelines**: 7 specialized agents (Init, Research, Planning, Executor, Docs, Sync, Doctor) for end-to-end development workflows.
|
|
15
|
+
- **Task Management**: Built-in CRUD operations for tracking high-level tasks via MCP tools.
|
|
15
16
|
|
|
16
17
|
---
|
|
17
18
|
|
|
@@ -58,7 +59,24 @@ RRCE-Workflow uses the [Model Context Protocol](https://modelcontextprotocol.io/
|
|
|
58
59
|
### Features
|
|
59
60
|
* **Universal Context**: Access your project's `project-context.md`, architecture docs, and task history from *any* MCP-enabled tool.
|
|
60
61
|
* **Cross-Project References**: Your AI can read documentation from Project A while working on Project B (perfect for monorepos or microservices).
|
|
61
|
-
* **
|
|
62
|
+
* **12 MCP Tools**: Including `search_knowledge`, `get_project_context`, `resolve_path`, task CRUD operations, and more.
|
|
63
|
+
|
|
64
|
+
### MCP Tools Reference
|
|
65
|
+
|
|
66
|
+
| Tool | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `resolve_path` | Resolve RRCE configuration paths (RRCE_DATA, WORKSPACE_ROOT, etc.) for a project |
|
|
69
|
+
| `list_projects` | List all projects exposed via MCP |
|
|
70
|
+
| `get_project_context` | Get the project-context.md for a specific project |
|
|
71
|
+
| `search_knowledge` | Semantic search (RAG) across project knowledge bases |
|
|
72
|
+
| `index_knowledge` | Update the semantic search index for a project |
|
|
73
|
+
| `list_agents` | List available RRCE agents and their arguments |
|
|
74
|
+
| `get_agent_prompt` | Get the system prompt for a specific agent with context injection |
|
|
75
|
+
| `list_tasks` | List all tasks for a project |
|
|
76
|
+
| `get_task` | Get details of a specific task |
|
|
77
|
+
| `create_task` | Create a new task in the project |
|
|
78
|
+
| `update_task` | Update an existing task's meta.json |
|
|
79
|
+
| `delete_task` | Delete a task from the project |
|
|
62
80
|
|
|
63
81
|
### Connecting Your IDE
|
|
64
82
|
|
|
@@ -149,36 +167,40 @@ Stores everything in a `.rrce-workflow` folder inside your project root.
|
|
|
149
167
|
|
|
150
168
|
---
|
|
151
169
|
|
|
152
|
-
##
|
|
170
|
+
## The Agent Pipeline
|
|
153
171
|
|
|
154
|
-
Once installed, you gain access to
|
|
172
|
+
Once installed, you gain access to 7 specialized agent workflows. Invoke them via your AI assistant's chat interface or through MCP tools.
|
|
155
173
|
|
|
156
|
-
| Agent | Purpose |
|
|
157
|
-
|
|
158
|
-
| **Init** |
|
|
159
|
-
| **Research** |
|
|
160
|
-
| **Planning** |
|
|
161
|
-
| **
|
|
162
|
-
| **Docs** |
|
|
163
|
-
| **Sync** |
|
|
164
|
-
| **Doctor** |
|
|
174
|
+
| Agent | ID | Purpose | Key Arguments |
|
|
175
|
+
|-------|----|---------|---------------|
|
|
176
|
+
| **Init** | `init` | Analyze codebase, establish project context and semantic index | `PROJECT_NAME` (optional) |
|
|
177
|
+
| **Research** | `research_discussion` | Interactive requirements clarification through dialogue | `TASK_SLUG`, `REQUEST` |
|
|
178
|
+
| **Planning** | `planning_discussion` | Transform research into actionable execution plan | `TASK_SLUG` |
|
|
179
|
+
| **Executor** | `executor` | Implement the plan - the ONLY agent authorized to modify code | `TASK_SLUG`, `BRANCH` |
|
|
180
|
+
| **Docs** | `documentation` | Generate project documentation (API, architecture, changelog) | `DOC_TYPE`, `TASK_SLUG` |
|
|
181
|
+
| **Sync** | `sync` | Reconcile knowledge base with current codebase state | `SCOPE` (optional) |
|
|
182
|
+
| **Doctor** | `doctor` | Analyze codebase health, identify issues, recommend improvements | `PROJECT_NAME`, `FOCUS_AREA` |
|
|
165
183
|
|
|
166
184
|
### Recommended Workflow
|
|
167
|
-
1.
|
|
168
|
-
2.
|
|
169
|
-
3.
|
|
170
|
-
4.
|
|
171
|
-
5.
|
|
185
|
+
1. **`init`**: "Analyze this codebase." → Creates `project-context.md` and semantic index.
|
|
186
|
+
2. **`research_discussion`**: "I need to add user auth." → Interactive requirements gathering.
|
|
187
|
+
3. **`planning_discussion`**: "Create a plan for user auth." → Generates implementation checklist.
|
|
188
|
+
4. **`executor`**: "Implement the auth plan." → Writes code, runs tests.
|
|
189
|
+
5. **`documentation`**: "Generate API docs." → Produces release-ready documentation.
|
|
190
|
+
6. **`sync`**: "Update knowledge." → Refreshes context for the next task.
|
|
172
191
|
|
|
173
192
|
---
|
|
174
193
|
|
|
175
|
-
##
|
|
194
|
+
## Semantic Search (RAG)
|
|
176
195
|
|
|
177
|
-
RRCE-Workflow includes a local, embedding-based search engine
|
|
178
|
-
- **Privacy First**: All embeddings are calculated locally on your CPU/GPU. No code leaves your machine.
|
|
179
|
-
- **Smart Context**: Allows the agent to find relevant code snippets via natural language queries (e.g., "Find the authentication middleware logic") even if keywords don't match exactly.
|
|
196
|
+
RRCE-Workflow includes a local, embedding-based search engine powered by `@xenova/transformers`.
|
|
180
197
|
|
|
181
|
-
|
|
198
|
+
- **Privacy First**: All embeddings are calculated locally. No code leaves your machine.
|
|
199
|
+
- **Full Codebase Indexing**: The `index_knowledge` tool scans your entire source tree (respecting skip lists like `node_modules`, `.git`).
|
|
200
|
+
- **Smart Fallback**: If RAG fails or isn't enabled, `search_knowledge` performs line-by-line text matching.
|
|
201
|
+
- **Model**: Uses `Xenova/all-MiniLM-L6-v2` by default (configurable per-project).
|
|
202
|
+
|
|
203
|
+
RAG is enabled by default in Express Setup. You can toggle it per-project in the MCP Dashboard or via `config.yaml`.
|
|
182
204
|
|
|
183
205
|
---
|
|
184
206
|
|
|
@@ -187,6 +209,16 @@ RAG is enabled by default in Express Setup. You can toggle it per-project in the
|
|
|
187
209
|
- **Node.js 18+**
|
|
188
210
|
- **Git**
|
|
189
211
|
|
|
212
|
+
## Tech Stack
|
|
213
|
+
|
|
214
|
+
| Component | Technology |
|
|
215
|
+
|-----------|------------|
|
|
216
|
+
| TUI Framework | Ink ^6.6.0 (React-based) |
|
|
217
|
+
| MCP Server | @modelcontextprotocol/sdk ^1.25.1 |
|
|
218
|
+
| Embeddings | @xenova/transformers ^2.17.2 |
|
|
219
|
+
| Build | esbuild |
|
|
220
|
+
| Runtime | Node.js >= 18 |
|
|
221
|
+
|
|
190
222
|
## License
|
|
191
223
|
|
|
192
224
|
MIT © RRCE Team
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
-
}) : x)(function(x) {
|
|
6
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
3
|
var __esm = (fn, res) => function __init() {
|
|
10
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
5
|
};
|
|
@@ -1568,6 +1562,33 @@ var init_rag = __esm({
|
|
|
1568
1562
|
logger.error(`[RAG] Failed to save index to ${this.indexPath}`, error);
|
|
1569
1563
|
}
|
|
1570
1564
|
}
|
|
1565
|
+
/**
|
|
1566
|
+
* Save index to a temp file and atomically replace
|
|
1567
|
+
*/
|
|
1568
|
+
saveIndexAtomic() {
|
|
1569
|
+
if (!this.index) return;
|
|
1570
|
+
const dir = path15.dirname(this.indexPath);
|
|
1571
|
+
if (!fs13.existsSync(dir)) {
|
|
1572
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
1573
|
+
}
|
|
1574
|
+
const tmpPath = `${this.indexPath}.tmp`;
|
|
1575
|
+
fs13.writeFileSync(tmpPath, JSON.stringify(this.index, null, 2));
|
|
1576
|
+
fs13.renameSync(tmpPath, this.indexPath);
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Save index only if enough time passed since last save
|
|
1580
|
+
*/
|
|
1581
|
+
maybeSaveIndex(force = false) {
|
|
1582
|
+
if (!this.index) return;
|
|
1583
|
+
const now = Date.now();
|
|
1584
|
+
const intervalMs = 1e3;
|
|
1585
|
+
const last = this.index.metadata?.lastSaveAt;
|
|
1586
|
+
if (force || last === void 0 || now - last >= intervalMs) {
|
|
1587
|
+
this.index.metadata = { ...this.index.metadata ?? {}, lastSaveAt: now };
|
|
1588
|
+
this.saveIndexAtomic();
|
|
1589
|
+
logger.info(`[RAG] Saved index (atomic) to ${this.indexPath} with ${this.index.chunks.length} chunks.`);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1571
1592
|
/**
|
|
1572
1593
|
* Generate embedding for text
|
|
1573
1594
|
*/
|
|
@@ -1618,7 +1639,7 @@ var init_rag = __esm({
|
|
|
1618
1639
|
mtime: mtime ?? Date.now(),
|
|
1619
1640
|
chunkCount: chunks.length
|
|
1620
1641
|
};
|
|
1621
|
-
this.
|
|
1642
|
+
this.maybeSaveIndex();
|
|
1622
1643
|
return true;
|
|
1623
1644
|
}
|
|
1624
1645
|
/**
|
|
@@ -1634,7 +1655,7 @@ var init_rag = __esm({
|
|
|
1634
1655
|
}
|
|
1635
1656
|
if (this.index.chunks.length !== initialCount) {
|
|
1636
1657
|
logger.info(`[RAG] Removed file ${filePath} from index (${initialCount - this.index.chunks.length} chunks removed)`);
|
|
1637
|
-
this.
|
|
1658
|
+
this.maybeSaveIndex(true);
|
|
1638
1659
|
}
|
|
1639
1660
|
}
|
|
1640
1661
|
/**
|
|
@@ -1657,7 +1678,7 @@ var init_rag = __esm({
|
|
|
1657
1678
|
this.loadIndex();
|
|
1658
1679
|
if (!this.index) return;
|
|
1659
1680
|
this.index.lastFullIndex = Date.now();
|
|
1660
|
-
this.
|
|
1681
|
+
this.maybeSaveIndex(true);
|
|
1661
1682
|
}
|
|
1662
1683
|
/**
|
|
1663
1684
|
* Search the index
|
|
@@ -1687,9 +1708,11 @@ var init_rag = __esm({
|
|
|
1687
1708
|
let normA = 0;
|
|
1688
1709
|
let normB = 0;
|
|
1689
1710
|
for (let i = 0; i < a.length; i++) {
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1711
|
+
const av = a[i] ?? 0;
|
|
1712
|
+
const bv = b[i] ?? 0;
|
|
1713
|
+
dotProduct += av * bv;
|
|
1714
|
+
normA += av * av;
|
|
1715
|
+
normB += bv * bv;
|
|
1693
1716
|
}
|
|
1694
1717
|
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
1695
1718
|
}
|
|
@@ -1722,9 +1745,87 @@ var init_rag = __esm({
|
|
|
1722
1745
|
}
|
|
1723
1746
|
});
|
|
1724
1747
|
|
|
1748
|
+
// src/mcp/services/indexing-jobs.ts
|
|
1749
|
+
var IndexingJobManager, indexingJobs;
|
|
1750
|
+
var init_indexing_jobs = __esm({
|
|
1751
|
+
"src/mcp/services/indexing-jobs.ts"() {
|
|
1752
|
+
"use strict";
|
|
1753
|
+
init_logger();
|
|
1754
|
+
IndexingJobManager = class {
|
|
1755
|
+
jobs = /* @__PURE__ */ new Map();
|
|
1756
|
+
getProgress(project) {
|
|
1757
|
+
const existing = this.jobs.get(project);
|
|
1758
|
+
if (existing) return { ...existing.progress };
|
|
1759
|
+
return {
|
|
1760
|
+
project,
|
|
1761
|
+
state: "idle",
|
|
1762
|
+
itemsDone: 0,
|
|
1763
|
+
itemsTotal: void 0
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
update(project, patch) {
|
|
1767
|
+
const existing = this.jobs.get(project);
|
|
1768
|
+
const next = {
|
|
1769
|
+
...existing?.progress ?? this.getProgress(project),
|
|
1770
|
+
...patch,
|
|
1771
|
+
project
|
|
1772
|
+
};
|
|
1773
|
+
this.jobs.set(project, { ...existing ?? { progress: next }, progress: next });
|
|
1774
|
+
}
|
|
1775
|
+
isRunning(project) {
|
|
1776
|
+
return this.getProgress(project).state === "running";
|
|
1777
|
+
}
|
|
1778
|
+
startOrStatus(project, runner) {
|
|
1779
|
+
const current = this.jobs.get(project);
|
|
1780
|
+
if (current?.progress.state === "running" && current.promise) {
|
|
1781
|
+
return {
|
|
1782
|
+
status: "already_running",
|
|
1783
|
+
state: "running",
|
|
1784
|
+
progress: { ...current.progress }
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
const startedAt = Date.now();
|
|
1788
|
+
const initial = {
|
|
1789
|
+
project,
|
|
1790
|
+
state: "running",
|
|
1791
|
+
startedAt,
|
|
1792
|
+
itemsDone: 0,
|
|
1793
|
+
itemsTotal: void 0,
|
|
1794
|
+
currentItem: void 0,
|
|
1795
|
+
lastError: void 0
|
|
1796
|
+
};
|
|
1797
|
+
const job = { progress: initial };
|
|
1798
|
+
this.jobs.set(project, job);
|
|
1799
|
+
job.promise = (async () => {
|
|
1800
|
+
try {
|
|
1801
|
+
await runner();
|
|
1802
|
+
this.update(project, { state: "complete", completedAt: Date.now(), currentItem: void 0 });
|
|
1803
|
+
} catch (err) {
|
|
1804
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1805
|
+
logger.error(`[RAG] Indexing job failed for '${project}'`, err);
|
|
1806
|
+
this.update(project, {
|
|
1807
|
+
state: "failed",
|
|
1808
|
+
completedAt: Date.now(),
|
|
1809
|
+
currentItem: void 0,
|
|
1810
|
+
lastError: msg
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
})();
|
|
1814
|
+
return {
|
|
1815
|
+
status: "started",
|
|
1816
|
+
state: "running",
|
|
1817
|
+
progress: { ...this.getProgress(project) }
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
indexingJobs = new IndexingJobManager();
|
|
1822
|
+
}
|
|
1823
|
+
});
|
|
1824
|
+
|
|
1725
1825
|
// src/mcp/resources.ts
|
|
1726
1826
|
import * as fs14 from "fs";
|
|
1727
1827
|
import * as path16 from "path";
|
|
1828
|
+
import * as os2 from "os";
|
|
1728
1829
|
import * as crypto from "crypto";
|
|
1729
1830
|
function resolveProjectPaths(project, pathInput) {
|
|
1730
1831
|
const config = loadMCPConfig();
|
|
@@ -1892,6 +1993,8 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1892
1993
|
if (projectFilter && project.name !== projectFilter) continue;
|
|
1893
1994
|
const permissions = getProjectPermissions(config, project.name, project.sourcePath || project.path);
|
|
1894
1995
|
if (!permissions.knowledge || !project.knowledgePath) continue;
|
|
1996
|
+
const indexingInProgress = indexingJobs.isRunning(project.name);
|
|
1997
|
+
const advisoryMessage = indexingInProgress ? "Indexing in progress; results may be stale/incomplete." : void 0;
|
|
1895
1998
|
const projConfig = config.projects.find(
|
|
1896
1999
|
(p) => p.path && normalizeProjectPath(p.path) === normalizeProjectPath(project.sourcePath || project.path) || !p.path && p.name === project.name
|
|
1897
2000
|
);
|
|
@@ -1908,7 +2011,9 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1908
2011
|
file: path16.relative(project.knowledgePath, r.filePath),
|
|
1909
2012
|
matches: [r.content],
|
|
1910
2013
|
// The chunk content is the match
|
|
1911
|
-
score: r.score
|
|
2014
|
+
score: r.score,
|
|
2015
|
+
indexingInProgress: indexingInProgress || void 0,
|
|
2016
|
+
advisoryMessage
|
|
1912
2017
|
});
|
|
1913
2018
|
}
|
|
1914
2019
|
continue;
|
|
@@ -1933,8 +2038,10 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1933
2038
|
results.push({
|
|
1934
2039
|
project: project.name,
|
|
1935
2040
|
file,
|
|
1936
|
-
matches: matches.slice(0, 5)
|
|
2041
|
+
matches: matches.slice(0, 5),
|
|
1937
2042
|
// Limit to 5 matches per file
|
|
2043
|
+
indexingInProgress: indexingInProgress || void 0,
|
|
2044
|
+
advisoryMessage
|
|
1938
2045
|
});
|
|
1939
2046
|
}
|
|
1940
2047
|
}
|
|
@@ -1946,20 +2053,44 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1946
2053
|
async function indexKnowledge(projectName, force = false) {
|
|
1947
2054
|
const config = loadMCPConfig();
|
|
1948
2055
|
const projects = getExposedProjects();
|
|
1949
|
-
const project = projects.find((
|
|
2056
|
+
const project = projects.find((p2) => p2.name === projectName || p2.path && p2.path === projectName);
|
|
1950
2057
|
if (!project) {
|
|
1951
|
-
return {
|
|
2058
|
+
return {
|
|
2059
|
+
state: "failed",
|
|
2060
|
+
status: "failed",
|
|
2061
|
+
success: false,
|
|
2062
|
+
message: `Project '${projectName}' not found`,
|
|
2063
|
+
filesIndexed: 0,
|
|
2064
|
+
filesSkipped: 0,
|
|
2065
|
+
progress: { itemsDone: 0 }
|
|
2066
|
+
};
|
|
1952
2067
|
}
|
|
1953
2068
|
const projConfig = config.projects.find(
|
|
1954
|
-
(
|
|
2069
|
+
(p2) => p2.path && normalizeProjectPath(p2.path) === normalizeProjectPath(project.sourcePath || project.path) || !p2.path && p2.name === project.name
|
|
1955
2070
|
) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
|
|
1956
2071
|
const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
|
|
1957
2072
|
if (!isEnabled) {
|
|
1958
|
-
return {
|
|
2073
|
+
return {
|
|
2074
|
+
state: "failed",
|
|
2075
|
+
status: "failed",
|
|
2076
|
+
success: false,
|
|
2077
|
+
message: "Semantic Search is not enabled for this project",
|
|
2078
|
+
filesIndexed: 0,
|
|
2079
|
+
filesSkipped: 0,
|
|
2080
|
+
progress: { itemsDone: 0 }
|
|
2081
|
+
};
|
|
1959
2082
|
}
|
|
1960
2083
|
const scanRoot = project.sourcePath || project.path || project.dataPath;
|
|
1961
2084
|
if (!fs14.existsSync(scanRoot)) {
|
|
1962
|
-
return {
|
|
2085
|
+
return {
|
|
2086
|
+
state: "failed",
|
|
2087
|
+
status: "failed",
|
|
2088
|
+
success: false,
|
|
2089
|
+
message: "Project root not found",
|
|
2090
|
+
filesIndexed: 0,
|
|
2091
|
+
filesSkipped: 0,
|
|
2092
|
+
progress: { itemsDone: 0 }
|
|
2093
|
+
};
|
|
1963
2094
|
}
|
|
1964
2095
|
const INDEXABLE_EXTENSIONS = [
|
|
1965
2096
|
".ts",
|
|
@@ -2000,18 +2131,37 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2000
2131
|
".less"
|
|
2001
2132
|
];
|
|
2002
2133
|
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv", "target", "vendor"];
|
|
2003
|
-
|
|
2134
|
+
const runIndexing = async () => {
|
|
2004
2135
|
const indexPath = path16.join(project.knowledgePath || path16.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
|
|
2005
2136
|
const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
|
|
2006
2137
|
const rag = new RAGService(indexPath, model);
|
|
2007
2138
|
let indexed = 0;
|
|
2008
2139
|
let skipped = 0;
|
|
2140
|
+
let itemsTotal = 0;
|
|
2141
|
+
let itemsDone = 0;
|
|
2142
|
+
const shouldSkipDir = (dirName) => SKIP_DIRS.includes(dirName) || dirName.startsWith(".");
|
|
2143
|
+
const preCount = (dir) => {
|
|
2144
|
+
const entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
2145
|
+
for (const entry of entries) {
|
|
2146
|
+
const fullPath = path16.join(dir, entry.name);
|
|
2147
|
+
if (entry.isDirectory()) {
|
|
2148
|
+
if (shouldSkipDir(entry.name)) continue;
|
|
2149
|
+
preCount(fullPath);
|
|
2150
|
+
} else if (entry.isFile()) {
|
|
2151
|
+
const ext = path16.extname(entry.name).toLowerCase();
|
|
2152
|
+
if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
|
|
2153
|
+
itemsTotal++;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
};
|
|
2157
|
+
preCount(scanRoot);
|
|
2158
|
+
indexingJobs.update(project.name, { itemsTotal });
|
|
2009
2159
|
const scanDir = async (dir) => {
|
|
2010
2160
|
const entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
2011
2161
|
for (const entry of entries) {
|
|
2012
2162
|
const fullPath = path16.join(dir, entry.name);
|
|
2013
2163
|
if (entry.isDirectory()) {
|
|
2014
|
-
if (
|
|
2164
|
+
if (shouldSkipDir(entry.name)) {
|
|
2015
2165
|
continue;
|
|
2016
2166
|
}
|
|
2017
2167
|
await scanDir(fullPath);
|
|
@@ -2021,6 +2171,7 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2021
2171
|
continue;
|
|
2022
2172
|
}
|
|
2023
2173
|
try {
|
|
2174
|
+
indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
|
|
2024
2175
|
const stat = fs14.statSync(fullPath);
|
|
2025
2176
|
const mtime = force ? void 0 : stat.mtimeMs;
|
|
2026
2177
|
const content = fs14.readFileSync(fullPath, "utf-8");
|
|
@@ -2031,6 +2182,12 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2031
2182
|
skipped++;
|
|
2032
2183
|
}
|
|
2033
2184
|
} catch (err) {
|
|
2185
|
+
} finally {
|
|
2186
|
+
itemsDone++;
|
|
2187
|
+
indexingJobs.update(project.name, { itemsDone });
|
|
2188
|
+
if (itemsDone % 10 === 0) {
|
|
2189
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
2190
|
+
}
|
|
2034
2191
|
}
|
|
2035
2192
|
}
|
|
2036
2193
|
}
|
|
@@ -2038,22 +2195,35 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2038
2195
|
await scanDir(scanRoot);
|
|
2039
2196
|
rag.markFullIndex();
|
|
2040
2197
|
const stats = rag.getStats();
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2198
|
+
const message = `Indexed ${indexed} files, skipped ${skipped} unchanged. Total: ${stats.totalChunks} chunks from ${stats.totalFiles} files.`;
|
|
2199
|
+
logger.info(`[RAG] ${project.name}: ${message}`);
|
|
2200
|
+
indexingJobs.update(project.name, { currentItem: void 0 });
|
|
2201
|
+
};
|
|
2202
|
+
const startResult = indexingJobs.startOrStatus(project.name, runIndexing);
|
|
2203
|
+
const p = startResult.progress;
|
|
2204
|
+
return {
|
|
2205
|
+
state: startResult.state,
|
|
2206
|
+
status: startResult.status,
|
|
2207
|
+
success: startResult.status === "started" || startResult.status === "already_running",
|
|
2208
|
+
message: startResult.status === "started" ? `Indexing started in background for '${project.name}'.` : `Indexing already running for '${project.name}'.`,
|
|
2209
|
+
filesIndexed: 0,
|
|
2210
|
+
filesSkipped: 0,
|
|
2211
|
+
progress: {
|
|
2212
|
+
itemsDone: p.itemsDone,
|
|
2213
|
+
itemsTotal: p.itemsTotal,
|
|
2214
|
+
currentItem: p.currentItem,
|
|
2215
|
+
startedAt: p.startedAt,
|
|
2216
|
+
completedAt: p.completedAt,
|
|
2217
|
+
lastError: p.lastError
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2050
2220
|
}
|
|
2051
2221
|
function getContextPreamble() {
|
|
2052
2222
|
const projects = getExposedProjects();
|
|
2053
2223
|
const activeProject = detectActiveProject();
|
|
2054
2224
|
let contextPreamble = "";
|
|
2055
2225
|
if (activeProject) {
|
|
2056
|
-
const rrceHome = process.env.RRCE_HOME || path16.join(
|
|
2226
|
+
const rrceHome = process.env.RRCE_HOME || path16.join(os2.homedir(), ".rrce-workflow");
|
|
2057
2227
|
const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
2058
2228
|
const rrceData = activeProject.dataPath;
|
|
2059
2229
|
contextPreamble += `
|
|
@@ -2123,7 +2293,7 @@ async function createTask(projectName, taskSlug, taskData) {
|
|
|
2123
2293
|
fs14.mkdirSync(path16.join(taskDir, "planning"), { recursive: true });
|
|
2124
2294
|
fs14.mkdirSync(path16.join(taskDir, "execution"), { recursive: true });
|
|
2125
2295
|
fs14.mkdirSync(path16.join(taskDir, "docs"), { recursive: true });
|
|
2126
|
-
const rrceHome = process.env.RRCE_HOME || path16.join(
|
|
2296
|
+
const rrceHome = process.env.RRCE_HOME || path16.join(os2.homedir(), ".rrce-workflow");
|
|
2127
2297
|
const templatePath = path16.join(rrceHome, "templates", "meta.template.json");
|
|
2128
2298
|
let meta = {
|
|
2129
2299
|
task_id: crypto.randomUUID(),
|
|
@@ -2194,6 +2364,7 @@ var init_resources = __esm({
|
|
|
2194
2364
|
init_detection();
|
|
2195
2365
|
init_detection_service();
|
|
2196
2366
|
init_rag();
|
|
2367
|
+
init_indexing_jobs();
|
|
2197
2368
|
init_paths();
|
|
2198
2369
|
}
|
|
2199
2370
|
});
|
|
@@ -3445,6 +3616,7 @@ var IndexingStatus;
|
|
|
3445
3616
|
var init_IndexingStatus = __esm({
|
|
3446
3617
|
"src/mcp/ui/IndexingStatus.tsx"() {
|
|
3447
3618
|
"use strict";
|
|
3619
|
+
init_indexing_jobs();
|
|
3448
3620
|
init_rag();
|
|
3449
3621
|
init_resources();
|
|
3450
3622
|
init_config_utils();
|
|
@@ -3461,9 +3633,14 @@ var init_IndexingStatus = __esm({
|
|
|
3461
3633
|
}
|
|
3462
3634
|
const enabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled || false;
|
|
3463
3635
|
if (!enabled) {
|
|
3636
|
+
const prog = indexingJobs.getProgress(project.name);
|
|
3464
3637
|
newStats.push({
|
|
3465
3638
|
projectName: project.name,
|
|
3466
3639
|
enabled: false,
|
|
3640
|
+
state: prog.state,
|
|
3641
|
+
itemsDone: prog.itemsDone,
|
|
3642
|
+
itemsTotal: prog.itemsTotal,
|
|
3643
|
+
currentItem: prog.currentItem,
|
|
3467
3644
|
totalFiles: 0,
|
|
3468
3645
|
totalChunks: 0
|
|
3469
3646
|
});
|
|
@@ -3473,17 +3650,27 @@ var init_IndexingStatus = __esm({
|
|
|
3473
3650
|
const indexPath = getRAGIndexPath(project);
|
|
3474
3651
|
const rag = new RAGService(indexPath, "dummy");
|
|
3475
3652
|
const s = rag.getStats();
|
|
3653
|
+
const prog = indexingJobs.getProgress(project.name);
|
|
3476
3654
|
newStats.push({
|
|
3477
3655
|
projectName: project.name,
|
|
3478
3656
|
enabled: true,
|
|
3657
|
+
state: prog.state,
|
|
3658
|
+
itemsDone: prog.itemsDone,
|
|
3659
|
+
itemsTotal: prog.itemsTotal,
|
|
3660
|
+
currentItem: prog.currentItem,
|
|
3479
3661
|
totalFiles: s.totalFiles,
|
|
3480
3662
|
totalChunks: s.totalChunks,
|
|
3481
3663
|
lastFullIndex: s.lastFullIndex
|
|
3482
3664
|
});
|
|
3483
3665
|
} catch (e) {
|
|
3666
|
+
const prog = indexingJobs.getProgress(project.name);
|
|
3484
3667
|
newStats.push({
|
|
3485
3668
|
projectName: project.name,
|
|
3486
3669
|
enabled: true,
|
|
3670
|
+
state: prog.state,
|
|
3671
|
+
itemsDone: prog.itemsDone,
|
|
3672
|
+
itemsTotal: prog.itemsTotal,
|
|
3673
|
+
currentItem: prog.currentItem,
|
|
3487
3674
|
totalFiles: 0,
|
|
3488
3675
|
totalChunks: 0,
|
|
3489
3676
|
error: String(e)
|
|
@@ -3506,13 +3693,16 @@ var init_IndexingStatus = __esm({
|
|
|
3506
3693
|
/* @__PURE__ */ jsxs8(Box9, { children: [
|
|
3507
3694
|
/* @__PURE__ */ jsx9(Box9, { width: 25, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Project" }) }),
|
|
3508
3695
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Status" }) }),
|
|
3696
|
+
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "State" }) }),
|
|
3697
|
+
/* @__PURE__ */ jsx9(Box9, { width: 18, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Progress" }) }),
|
|
3509
3698
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Indexed Files" }) }),
|
|
3510
3699
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Total Chunks" }) }),
|
|
3511
3700
|
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Last Index" }) })
|
|
3512
3701
|
] }),
|
|
3513
3702
|
stats.length === 0 ? /* @__PURE__ */ jsx9(Text9, { color: "dim", children: "No exposed projects found." }) : stats.map((s) => /* @__PURE__ */ jsxs8(Box9, { marginTop: 0, children: [
|
|
3514
3703
|
/* @__PURE__ */ jsx9(Box9, { width: 25, children: /* @__PURE__ */ jsx9(Text9, { color: "white", children: s.projectName }) }),
|
|
3515
|
-
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { color: s.enabled ? "green" : "dim", children: s.enabled ?
|
|
3704
|
+
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { color: s.state === "running" ? "yellow" : s.state === "failed" ? "red" : s.enabled ? "green" : "dim", children: s.enabled ? s.state : "disabled" }) }),
|
|
3705
|
+
/* @__PURE__ */ jsx9(Box9, { width: 18, children: /* @__PURE__ */ jsx9(Text9, { children: s.state === "running" ? `${s.itemsDone}/${s.itemsTotal ?? "?"}` : "-" }) }),
|
|
3516
3706
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { children: s.enabled ? s.totalFiles : "-" }) }),
|
|
3517
3707
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { children: s.enabled ? s.totalChunks : "-" }) }),
|
|
3518
3708
|
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text9, { children: s.lastFullIndex ? new Date(s.lastFullIndex).toLocaleTimeString() : "-" }) })
|
package/docs/architecture.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# RRCE-Workflow Architecture
|
|
2
2
|
|
|
3
3
|
> RR Context Engineering Workflow - A selection-agnostic agentic workflow system
|
|
4
|
+
>
|
|
5
|
+
> **Version**: 0.2.91 | **Last Updated**: 2025-12-31
|
|
4
6
|
|
|
5
7
|
## Overview
|
|
6
8
|
|
|
7
9
|
RRCE-Workflow is a TUI-based agentic code workflow generator designed to work seamlessly across:
|
|
8
|
-
- **
|
|
10
|
+
- **OpenCode** (Native agentic TUI environment with custom Primary Agents)
|
|
11
|
+
- **GitHub Copilot** (VSCode with MCP extension)
|
|
9
12
|
- **Antigravity IDE** (Google's agentic coding environment)
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **Claude Desktop**
|
|
13
|
+
- **Claude Desktop** (MCP Server integration)
|
|
14
|
+
- **Any MCP-compatible client**
|
|
13
15
|
|
|
14
|
-
The system provides a structured multi-agent pipeline for software development tasks, with persistent knowledge caching and workspace-aware context management.
|
|
16
|
+
The system provides a structured multi-agent pipeline (7 agents) for software development tasks, with persistent knowledge caching, semantic search (RAG), and workspace-aware context management.
|
|
15
17
|
|
|
16
18
|
## Core Principles
|
|
17
19
|
|
|
@@ -24,38 +26,79 @@ The system provides a structured multi-agent pipeline for software development t
|
|
|
24
26
|
|
|
25
27
|
## Directory Structure
|
|
26
28
|
|
|
29
|
+
### Source Code Organization
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
rrce-workflow/
|
|
33
|
+
├── agent-core/ # Agent prompts and templates (Source of Truth)
|
|
34
|
+
│ ├── prompts/ # 7 agent system prompts (doctor, executor, init, etc.)
|
|
35
|
+
│ ├── templates/ # Output templates for agents
|
|
36
|
+
│ │ └── docs/ # Doc-type specific templates
|
|
37
|
+
│ └── docs/ # Internal documentation (path-resolution.md)
|
|
38
|
+
├── bin/ # Executable entry points
|
|
39
|
+
│ └── rrce-workflow.js # NPM binary wrapper
|
|
40
|
+
├── docs/ # High-level architecture docs (this file)
|
|
41
|
+
├── scripts/ # Maintenance and verification scripts
|
|
42
|
+
├── src/ # Source code
|
|
43
|
+
│ ├── commands/ # CLI/TUI command implementations
|
|
44
|
+
│ │ └── wizard/ # Interactive setup wizard (setup-flow, link-flow, etc.)
|
|
45
|
+
│ ├── lib/ # Core utilities
|
|
46
|
+
│ │ ├── detection.ts # Project scanning and detection (DetectedProject)
|
|
47
|
+
│ │ ├── detection-service.ts # Singleton project service
|
|
48
|
+
│ │ ├── git.ts # Git utilities
|
|
49
|
+
│ │ ├── paths.ts # Path resolution (RRCE_HOME, RRCE_DATA, etc.)
|
|
50
|
+
│ │ └── preferences.ts # User preference storage
|
|
51
|
+
│ ├── mcp/ # MCP Server implementation
|
|
52
|
+
│ │ ├── handlers/ # Decomposed request handlers
|
|
53
|
+
│ │ │ ├── prompts.ts # Prompt/agent handlers
|
|
54
|
+
│ │ │ ├── resources.ts # Resource handlers
|
|
55
|
+
│ │ │ └── tools.ts # 12 MCP tools (search, index, tasks, etc.)
|
|
56
|
+
│ │ ├── services/ # Backend services
|
|
57
|
+
│ │ │ └── rag.ts # Semantic search with @xenova/transformers
|
|
58
|
+
│ │ ├── ui/ # TUI components (Ink/React)
|
|
59
|
+
│ │ │ └── components/ # Reusable UI components
|
|
60
|
+
│ │ ├── config.ts # MCP configuration management
|
|
61
|
+
│ │ ├── resources.ts # Project data access utilities
|
|
62
|
+
│ │ └── server.ts # MCP Server entry point (Stdio transport)
|
|
63
|
+
│ └── types/ # Global TypeScript definitions
|
|
64
|
+
└── temp_rag_test/ # RAG testing environment
|
|
65
|
+
```
|
|
66
|
+
|
|
27
67
|
### Global Installation (`~/.rrce-workflow/`)
|
|
28
68
|
|
|
29
69
|
```
|
|
30
70
|
~/.rrce-workflow/
|
|
31
|
-
├──
|
|
32
|
-
├──
|
|
33
|
-
|
|
34
|
-
│ ├──
|
|
35
|
-
│
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
├──
|
|
44
|
-
|
|
45
|
-
└── tasks/ # Task state and artifacts
|
|
71
|
+
├── mcp.yaml # MCP server configuration (projects, permissions)
|
|
72
|
+
├── preferences.json # User preferences (global path overrides)
|
|
73
|
+
├── templates/ # Default template store
|
|
74
|
+
│ ├── meta.template.json # Task metadata template
|
|
75
|
+
│ └── docs/ # Doc-type specific templates
|
|
76
|
+
└── workspaces/ # Project-scoped data (Global Mode)
|
|
77
|
+
└── <workspace-name>/ # Named by project, not hash
|
|
78
|
+
├── config.yaml # Project configuration
|
|
79
|
+
├── knowledge/ # Project domain knowledge
|
|
80
|
+
│ ├── project-context.md # Main context file
|
|
81
|
+
│ ├── embeddings.json # RAG vector index
|
|
82
|
+
│ └── <topic>.md # Additional knowledge files
|
|
83
|
+
├── refs/ # Reference documents
|
|
84
|
+
└── tasks/ # Task state and artifacts
|
|
46
85
|
└── <task-slug>/
|
|
47
|
-
├── meta.json
|
|
48
|
-
├── research/
|
|
49
|
-
├── planning/
|
|
50
|
-
├── execution/
|
|
51
|
-
└── docs/
|
|
86
|
+
├── meta.json # Task metadata, checklist, agent status
|
|
87
|
+
├── research/ # Research artifacts
|
|
88
|
+
├── planning/ # Planning artifacts
|
|
89
|
+
├── execution/ # Execution logs
|
|
90
|
+
└── docs/ # Generated documentation
|
|
52
91
|
```
|
|
53
92
|
|
|
54
|
-
### Workspace
|
|
93
|
+
### Workspace Mode (`.rrce-workflow/`)
|
|
55
94
|
|
|
56
95
|
```
|
|
57
96
|
<workspace>/
|
|
58
|
-
└── .rrce-workflow
|
|
97
|
+
└── .rrce-workflow/
|
|
98
|
+
├── config.yaml # Project-specific config
|
|
99
|
+
├── knowledge/ # Project knowledge (same structure as global)
|
|
100
|
+
├── refs/
|
|
101
|
+
└── tasks/
|
|
59
102
|
```
|
|
60
103
|
|
|
61
104
|
---
|
|
@@ -69,19 +112,28 @@ The system provides a structured multi-agent pipeline for software development t
|
|
|
69
112
|
| `global` (default) | `~/.rrce-workflow/workspaces/<workspace-name>/` | Non-intrusive, survives repo deletion |
|
|
70
113
|
| `workspace` | `<workspace>/.rrce-workflow/` | Portable, team-shareable |
|
|
71
114
|
|
|
72
|
-
Configure via
|
|
115
|
+
Configure via `config.yaml`:
|
|
73
116
|
```yaml
|
|
74
|
-
|
|
75
|
-
|
|
117
|
+
mode: global # or: workspace
|
|
118
|
+
name: my-project
|
|
119
|
+
sourcePath: /path/to/source # For global mode: links data back to source
|
|
76
120
|
```
|
|
77
121
|
|
|
122
|
+
### Key Path Functions (`src/lib/paths.ts`)
|
|
123
|
+
|
|
124
|
+
| Function | Purpose |
|
|
125
|
+
|----------|---------|
|
|
126
|
+
| `getEffectiveGlobalPath()` | Returns RRCE_HOME respecting user preferences |
|
|
127
|
+
| `getConfigPath(workspaceRoot)` | Finds config.yaml (local or global) |
|
|
128
|
+
| `resolveDataPath(mode, name, root)` | Resolves RRCE_DATA based on storage mode |
|
|
129
|
+
| `detectWorkspaceRoot()` | Walks up from CWD to find project root |
|
|
130
|
+
|
|
78
131
|
### Environment Variables
|
|
79
132
|
|
|
80
133
|
| Variable | Purpose | Default |
|
|
81
134
|
|----------|---------|---------|
|
|
82
135
|
| `RRCE_HOME` | Global installation path | `~/.rrce-workflow` |
|
|
83
136
|
| `RRCE_WORKSPACE` | Explicit workspace root | Auto-detected |
|
|
84
|
-
| `RRCE_AUTHOR` | Default author name | From `config.yaml` |
|
|
85
137
|
|
|
86
138
|
### Template Variables
|
|
87
139
|
|
|
@@ -89,7 +141,7 @@ storage:
|
|
|
89
141
|
|----------|-------------|
|
|
90
142
|
| `{{RRCE_HOME}}` | Global installation path |
|
|
91
143
|
| `{{RRCE_DATA}}` | Data path (based on storage mode) |
|
|
92
|
-
| `{{WORKSPACE_ROOT}}` | Workspace directory |
|
|
144
|
+
| `{{WORKSPACE_ROOT}}` | Workspace directory (source code location) |
|
|
93
145
|
| `{{WORKSPACE_NAME}}` | Project name (from config or directory) |
|
|
94
146
|
|
|
95
147
|
### Workspace Detection Algorithm
|
|
@@ -98,10 +150,32 @@ storage:
|
|
|
98
150
|
1. If $RRCE_WORKSPACE is set → use it
|
|
99
151
|
2. Walk up from CWD, find first directory containing:
|
|
100
152
|
- .git/
|
|
101
|
-
- .rrce-workflow.yaml
|
|
153
|
+
- .rrce-workflow/config.yaml (new)
|
|
154
|
+
- .rrce-workflow.yaml (legacy)
|
|
102
155
|
3. Fall back to CWD
|
|
103
156
|
```
|
|
104
157
|
|
|
158
|
+
### Project Detection (`src/lib/detection.ts`)
|
|
159
|
+
|
|
160
|
+
The `DetectedProject` interface captures:
|
|
161
|
+
```typescript
|
|
162
|
+
interface DetectedProject {
|
|
163
|
+
name: string;
|
|
164
|
+
path: string; // Absolute path to project root
|
|
165
|
+
dataPath: string; // Path to .rrce-workflow data directory
|
|
166
|
+
source: 'global' | 'local';
|
|
167
|
+
sourcePath?: string; // For global mode: actual source code location
|
|
168
|
+
knowledgePath?: string;
|
|
169
|
+
tasksPath?: string;
|
|
170
|
+
semanticSearchEnabled?: boolean;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Scanning priority:
|
|
175
|
+
1. Known projects from MCP config (name + path)
|
|
176
|
+
2. Global storage (`~/.rrce-workflow/workspaces/`)
|
|
177
|
+
3. Home directory recursive scan (up to depth 5)
|
|
178
|
+
|
|
105
179
|
### Cross-Project References
|
|
106
180
|
|
|
107
181
|
Reference another project's context when needed:
|
|
@@ -125,13 +199,13 @@ Reference another project's context when needed:
|
|
|
125
199
|
└────────┬────────┘
|
|
126
200
|
│
|
|
127
201
|
▼
|
|
128
|
-
project-context.md
|
|
202
|
+
project-context.md + embeddings.json
|
|
129
203
|
│
|
|
130
204
|
┌────────────────────────────────────┴────────────────────────────────────┐
|
|
131
205
|
▼ │
|
|
132
206
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
133
207
|
│ Research │────▶│ Planning │────▶│ Executor │────▶│ Documentation │
|
|
134
|
-
│
|
|
208
|
+
│ Discussion │ │ Discussion │ │ (Code Changes) │ │ │
|
|
135
209
|
└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
136
210
|
│ │ │ │
|
|
137
211
|
▼ ▼ ▼ ▼
|
|
@@ -139,43 +213,74 @@ Reference another project's context when needed:
|
|
|
139
213
|
│ │ │ │
|
|
140
214
|
└───────────────────────┴───────────────────────┴───────────────────────┘
|
|
141
215
|
│
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
216
|
+
┌────────┴────────┐
|
|
217
|
+
▼ ▼
|
|
218
|
+
{{RRCE_DATA}}/ ┌─────────────────┐
|
|
219
|
+
knowledge/ │ Sync │
|
|
220
|
+
│ (Reconciliation)│
|
|
221
|
+
└────────┬────────┘
|
|
222
|
+
│
|
|
223
|
+
┌────────┴────────┐
|
|
224
|
+
▼ ▼
|
|
225
|
+
Doctor (Next Task)
|
|
226
|
+
(Health Check)
|
|
145
227
|
```
|
|
146
228
|
|
|
147
229
|
### Agent Responsibilities
|
|
148
230
|
|
|
149
|
-
| Agent | Role | Input | Output |
|
|
150
|
-
|
|
151
|
-
| **Init** | Analyze codebase, establish project context | Workspace files | `project-context.md` |
|
|
152
|
-
| **Research
|
|
153
|
-
| **Planning
|
|
154
|
-
| **Executor** | Implement and verify | Plan + skill scope | Code + execution log |
|
|
155
|
-
| **Documentation** | Synthesize and handover | All artifacts | Release-ready docs |
|
|
156
|
-
| **Sync** | Reconcile knowledge | Codebase state | Updated knowledge files |
|
|
231
|
+
| Agent | ID | Role | Input | Output |
|
|
232
|
+
|-------|-----|------|-------|--------|
|
|
233
|
+
| **Init** | `init` | Analyze codebase, establish project context, build RAG index | Workspace files | `project-context.md`, `embeddings.json` |
|
|
234
|
+
| **Research** | `research_discussion` | Interactive requirements clarification, surface risks | User request + context | Research brief |
|
|
235
|
+
| **Planning** | `planning_discussion` | Create actionable execution plan with checklist | Research brief | Prioritized task breakdown |
|
|
236
|
+
| **Executor** | `executor` | Implement and verify - ONLY agent that modifies code | Plan + skill scope | Code + execution log |
|
|
237
|
+
| **Documentation** | `documentation` | Synthesize and handover | All artifacts | Release-ready docs |
|
|
238
|
+
| **Sync** | `sync` | Reconcile knowledge with codebase state | Codebase state | Updated knowledge files |
|
|
239
|
+
| **Doctor** | `doctor` | Analyze codebase health using semantic search | Project + focus area | Health report, improvement tasks |
|
|
157
240
|
|
|
158
241
|
---
|
|
159
242
|
|
|
160
243
|
## Configuration
|
|
161
244
|
|
|
162
|
-
###
|
|
245
|
+
### MCP Configuration (`~/.rrce-workflow/mcp.yaml`)
|
|
163
246
|
|
|
164
247
|
```yaml
|
|
165
|
-
|
|
248
|
+
# Projects exposed to MCP clients
|
|
249
|
+
projects:
|
|
250
|
+
- name: my-project
|
|
251
|
+
path: /path/to/my-project
|
|
252
|
+
permissions:
|
|
253
|
+
knowledge: true
|
|
254
|
+
tasks: true
|
|
255
|
+
prompts: true
|
|
256
|
+
semanticSearch:
|
|
257
|
+
enabled: true
|
|
258
|
+
model: Xenova/all-MiniLM-L6-v2
|
|
259
|
+
```
|
|
166
260
|
|
|
167
|
-
|
|
168
|
-
author: "your-name"
|
|
169
|
-
email: "your@email.com"
|
|
261
|
+
### Project Config (`<workspace>/.rrce-workflow/config.yaml` or global)
|
|
170
262
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
#
|
|
177
|
-
|
|
178
|
-
|
|
263
|
+
```yaml
|
|
264
|
+
name: my-project
|
|
265
|
+
mode: global # or: workspace
|
|
266
|
+
sourcePath: /path/to/source # For global mode
|
|
267
|
+
|
|
268
|
+
# Semantic search configuration
|
|
269
|
+
semantic_search:
|
|
270
|
+
enabled: true
|
|
271
|
+
|
|
272
|
+
# Cross-project linking
|
|
273
|
+
linked_projects:
|
|
274
|
+
- other-project
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### User Preferences (`~/.rrce-workflow/preferences.json`)
|
|
278
|
+
|
|
279
|
+
```json
|
|
280
|
+
{
|
|
281
|
+
"defaultGlobalPath": "/custom/path/.rrce-workflow",
|
|
282
|
+
"useCustomGlobalPath": true
|
|
283
|
+
}
|
|
179
284
|
```
|
|
180
285
|
|
|
181
286
|
### Project Config (`<workspace>/.rrce-workflow.yaml`)
|
|
@@ -205,89 +310,78 @@ author: "maintainer-name" # Overrides global config for this project
|
|
|
205
310
|
|
|
206
311
|
## Prompt Frontmatter Schema
|
|
207
312
|
|
|
208
|
-
All agent prompts use YAML frontmatter for metadata
|
|
313
|
+
All agent prompts in `agent-core/prompts/` use YAML frontmatter for metadata:
|
|
209
314
|
|
|
210
315
|
```yaml
|
|
211
316
|
---
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
317
|
+
name: RRCE Executor
|
|
318
|
+
description: Execute the planned tasks to deliver working code and tests.
|
|
319
|
+
tools:
|
|
320
|
+
- read
|
|
321
|
+
- write
|
|
322
|
+
- edit
|
|
323
|
+
- bash
|
|
324
|
+
- glob
|
|
325
|
+
- grep
|
|
326
|
+
- search_knowledge # MCP tool (becomes rrce_search_knowledge in OpenCode)
|
|
327
|
+
- get_project_context # MCP tool
|
|
328
|
+
- update_task # MCP tool
|
|
329
|
+
arguments:
|
|
330
|
+
- name: TASK_SLUG
|
|
331
|
+
description: Enter the task slug to execute
|
|
332
|
+
required: true
|
|
333
|
+
- name: BRANCH
|
|
334
|
+
description: Git branch for the work
|
|
335
|
+
required: false
|
|
225
336
|
---
|
|
226
|
-
```
|
|
227
337
|
|
|
228
|
-
|
|
338
|
+
# Agent System Prompt Content...
|
|
339
|
+
```
|
|
229
340
|
|
|
230
|
-
|
|
341
|
+
### Tool Categories
|
|
231
342
|
|
|
232
|
-
|
|
|
233
|
-
|
|
234
|
-
|
|
|
235
|
-
|
|
|
343
|
+
| Category | Tools | Notes |
|
|
344
|
+
|----------|-------|-------|
|
|
345
|
+
| **Host Tools** | `read`, `write`, `edit`, `bash`, `grep`, `glob`, `webfetch` | Native to host environment |
|
|
346
|
+
| **MCP Tools** | `search_knowledge`, `get_project_context`, `list_tasks`, etc. | Prefixed with `rrce_` in OpenCode |
|
|
236
347
|
|
|
237
348
|
---
|
|
238
349
|
|
|
239
350
|
## Multi-Tool Integration
|
|
240
351
|
|
|
241
|
-
RRCE-Workflow prompts are designed to work across multiple AI coding tools
|
|
352
|
+
RRCE-Workflow prompts are designed to work across multiple AI coding tools via MCP and IDE-specific agent generation.
|
|
242
353
|
|
|
243
354
|
### Tool Support Matrix
|
|
244
355
|
|
|
245
|
-
| Tool |
|
|
246
|
-
|
|
247
|
-
| **
|
|
248
|
-
| **
|
|
249
|
-
| **GitHub Copilot (VSCode)** | `.
|
|
250
|
-
| **
|
|
251
|
-
|
|
252
|
-
### Wizard Command
|
|
356
|
+
| Tool | MCP Config Location | Agent Location | Notes |
|
|
357
|
+
|------|---------------------|----------------|-------|
|
|
358
|
+
| **OpenCode** | `~/.config/opencode/opencode.json` | `.opencode/agent/rrce-*.md` | Custom Primary Agents (Tab to switch) |
|
|
359
|
+
| **Antigravity IDE** | `~/.gemini/antigravity/mcp_config.json` | `.agent/workflows/*.md` | Native workflow support |
|
|
360
|
+
| **GitHub Copilot (VSCode)** | `.vscode/mcp.json` or global settings | `.github/prompts/*.prompt.md` | Custom agents format |
|
|
361
|
+
| **Claude Desktop** | `~/.config/claude/claude_desktop_config.json` | N/A | MCP Server only |
|
|
253
362
|
|
|
254
|
-
|
|
363
|
+
### OpenCode Agent Transformation
|
|
255
364
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
│ Which AI tools do you use? │
|
|
264
|
-
│ │
|
|
265
|
-
│ [x] GitHub Copilot (VSCode) │
|
|
266
|
-
│ [x] Antigravity IDE │
|
|
267
|
-
│ [ ] Copilot CLI only │
|
|
268
|
-
│ │
|
|
269
|
-
│ ───────────────────────────────────────────────────── │
|
|
270
|
-
│ │
|
|
271
|
-
│ ✓ Created .github/prompts/*.prompt.md │
|
|
272
|
-
│ ✓ Created .agent/workflows/*.md │
|
|
273
|
-
│ ✓ Initialized project context │
|
|
274
|
-
│ │
|
|
275
|
-
└─────────────────────────────────────────────────────────┘
|
|
276
|
-
```
|
|
365
|
+
When generating agents for OpenCode (`src/commands/wizard/utils.ts`):
|
|
366
|
+
- **Mode**: Set to `primary` (enables Tab cycling in TUI)
|
|
367
|
+
- **Tools**:
|
|
368
|
+
- Host tools (`read`, `write`, `edit`, `bash`, `grep`, `glob`, `webfetch`) pass through as-is
|
|
369
|
+
- MCP tools are prefixed with `rrce_` (e.g., `rrce_search_knowledge`)
|
|
370
|
+
- Tool list respects per-agent frontmatter restrictions
|
|
371
|
+
- **Naming**: Agents prefixed with `rrce-` to avoid collisions
|
|
277
372
|
|
|
278
373
|
### Generated Files
|
|
279
374
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
**For GitHub Copilot (VSCode):**
|
|
375
|
+
**For OpenCode:**
|
|
283
376
|
```
|
|
284
|
-
.
|
|
285
|
-
├── init.
|
|
286
|
-
├── research.
|
|
287
|
-
├── planning.
|
|
288
|
-
├── executor.
|
|
289
|
-
├── documentation.
|
|
290
|
-
|
|
377
|
+
.opencode/agent/
|
|
378
|
+
├── rrce-init.md
|
|
379
|
+
├── rrce-research.md
|
|
380
|
+
├── rrce-planning.md
|
|
381
|
+
├── rrce-executor.md
|
|
382
|
+
├── rrce-documentation.md
|
|
383
|
+
├── rrce-sync.md
|
|
384
|
+
└── rrce-doctor.md
|
|
291
385
|
```
|
|
292
386
|
|
|
293
387
|
**For Antigravity IDE:**
|
|
@@ -298,55 +392,81 @@ When you run `rrce-workflow wizard`, it creates:
|
|
|
298
392
|
├── planning.md
|
|
299
393
|
├── executor.md
|
|
300
394
|
├── documentation.md
|
|
301
|
-
|
|
395
|
+
├── sync.md
|
|
396
|
+
└── doctor.md
|
|
302
397
|
```
|
|
303
398
|
|
|
304
|
-
**For
|
|
399
|
+
**For GitHub Copilot (VSCode):**
|
|
305
400
|
```
|
|
306
|
-
.
|
|
307
|
-
├──
|
|
308
|
-
├──
|
|
309
|
-
├──
|
|
310
|
-
├──
|
|
311
|
-
├──
|
|
312
|
-
|
|
401
|
+
.github/prompts/
|
|
402
|
+
├── init.prompt.md
|
|
403
|
+
├── research.prompt.md
|
|
404
|
+
├── planning.prompt.md
|
|
405
|
+
├── executor.prompt.md
|
|
406
|
+
├── documentation.prompt.md
|
|
407
|
+
├── sync.prompt.md
|
|
408
|
+
└── doctor.prompt.md
|
|
313
409
|
```
|
|
314
410
|
|
|
315
|
-
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## MCP Server Architecture
|
|
414
|
+
|
|
415
|
+
The MCP Server (`src/mcp/`) provides the bridge between project knowledge and AI agents.
|
|
416
|
+
|
|
417
|
+
### Components
|
|
418
|
+
|
|
419
|
+
| Component | Location | Purpose |
|
|
420
|
+
|-----------|----------|---------|
|
|
421
|
+
| **Server Entry** | `src/mcp/server.ts` | Initializes server, registers handlers, manages Stdio transport |
|
|
422
|
+
| **Tool Handlers** | `src/mcp/handlers/tools.ts` | 12 MCP tools (search, index, tasks, resolve_path, etc.) |
|
|
423
|
+
| **Prompt Handlers** | `src/mcp/handlers/prompts.ts` | Agent system prompts with context injection |
|
|
424
|
+
| **Resource Handlers** | `src/mcp/handlers/resources.ts` | Knowledge files and project context as readable resources |
|
|
425
|
+
| **RAG Service** | `src/mcp/services/rag.ts` | Semantic search with @xenova/transformers |
|
|
426
|
+
| **Resources Utilities** | `src/mcp/resources.ts` | Project data access, task CRUD, context preamble generation |
|
|
427
|
+
|
|
428
|
+
### Context Injection
|
|
316
429
|
|
|
317
|
-
|
|
430
|
+
When an agent requests a prompt via `get_agent_prompt`, the server injects a **Context Preamble** containing:
|
|
431
|
+
- **System Resolved Paths**: Pre-resolved `RRCE_DATA`, `WORKSPACE_ROOT`, `RRCE_HOME`
|
|
432
|
+
- **Available Projects**: List of exposed projects with active project marked
|
|
433
|
+
- **Active Workspace**: Current project context for file operations
|
|
318
434
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
|
322
|
-
|
|
435
|
+
### Semantic Search (RAG)
|
|
436
|
+
|
|
437
|
+
| Feature | Implementation |
|
|
438
|
+
|---------|----------------|
|
|
439
|
+
| **Embedding Model** | `Xenova/all-MiniLM-L6-v2` (configurable) |
|
|
440
|
+
| **Index Location** | `<knowledge>/embeddings.json` |
|
|
441
|
+
| **Similarity** | Cosine similarity |
|
|
442
|
+
| **Indexable Extensions** | `.ts`, `.tsx`, `.js`, `.py`, `.go`, `.rs`, `.md`, etc. |
|
|
443
|
+
| **Skip Directories** | `node_modules`, `.git`, `dist`, `build`, etc. |
|
|
323
444
|
|
|
324
445
|
---
|
|
325
446
|
|
|
326
|
-
## Installation Flow
|
|
447
|
+
## Installation Flow
|
|
327
448
|
|
|
449
|
+
```bash
|
|
450
|
+
# Option 1: MCP Dashboard (recommended)
|
|
451
|
+
npx rrce-workflow mcp
|
|
452
|
+
|
|
453
|
+
# Option 2: Project Setup Wizard
|
|
454
|
+
cd your-project
|
|
455
|
+
npx rrce-workflow
|
|
456
|
+
|
|
457
|
+
# Option 3: Start MCP Server directly (for IDE config)
|
|
458
|
+
npx rrce-workflow mcp start
|
|
328
459
|
```
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
│ │
|
|
340
|
-
│ ───────────────────────────────────────────────────── │
|
|
341
|
-
│ │
|
|
342
|
-
│ ✓ Created ~/.rrce-workflow/config.yaml │
|
|
343
|
-
│ ✓ Installed default templates │
|
|
344
|
-
│ ✓ Ready to use! │
|
|
345
|
-
│ │
|
|
346
|
-
│ Run `rrce-workflow help` for available commands. │
|
|
347
|
-
│ │
|
|
348
|
-
└─────────────────────────────────────────────────────────┘
|
|
349
|
-
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Key Design Patterns
|
|
464
|
+
|
|
465
|
+
1. **MCP Decoupling**: Handlers separated from server instance for maintainability
|
|
466
|
+
2. **TUI/MCP Separation**: MCP runs in "interactive" mode to avoid stdio conflicts with TUI
|
|
467
|
+
3. **Prompt Parsing**: Frontmatter-based prompts with variable injection
|
|
468
|
+
4. **Hybrid Storage**: Global mode (clean repos) vs Workspace mode (portable)
|
|
469
|
+
5. **DetectedProject.sourcePath**: For global mode, links data back to actual source location
|
|
350
470
|
|
|
351
471
|
---
|
|
352
472
|
|
|
@@ -355,5 +475,7 @@ $ npx rrce-workflow
|
|
|
355
475
|
- [ ] Web UI for knowledge browsing
|
|
356
476
|
- [ ] Cross-project knowledge sharing (opt-in)
|
|
357
477
|
- [ ] Plugin system for custom agents
|
|
358
|
-
- [ ]
|
|
478
|
+
- [ ] Comprehensive test suite (Jest/Vitest)
|
|
479
|
+
- [ ] CI/CD with GitHub Actions
|
|
480
|
+
- [ ] Cross-platform parity (Windows/macOS)
|
|
359
481
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rrce-workflow",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.93",
|
|
4
4
|
"description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
|
|
5
5
|
"author": "RRCE Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,10 @@
|
|
|
39
39
|
"wizard": "npx tsx src/index.ts wizard",
|
|
40
40
|
"start": "npx tsx src/index.ts",
|
|
41
41
|
"build": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --packages=external",
|
|
42
|
-
"prepublishOnly": "npm run build"
|
|
42
|
+
"prepublishOnly": "npm run build",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest",
|
|
45
|
+
"test:coverage": "vitest run --coverage"
|
|
43
46
|
},
|
|
44
47
|
"engines": {
|
|
45
48
|
"node": ">=18"
|
|
@@ -62,8 +65,10 @@
|
|
|
62
65
|
"devDependencies": {
|
|
63
66
|
"@types/node": "^25.0.3",
|
|
64
67
|
"@types/react": "^19.2.7",
|
|
68
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
65
69
|
"esbuild": "^0.27.2",
|
|
66
70
|
"tsx": "^4.21.0",
|
|
67
|
-
"typescript": "^5.9.3"
|
|
71
|
+
"typescript": "^5.9.3",
|
|
72
|
+
"vitest": "^4.0.16"
|
|
68
73
|
}
|
|
69
74
|
}
|