rrce-workflow 0.3.20 → 0.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-core/prompts/sync.md +9 -8
- package/dist/index.js +174 -146
- package/package.json +1 -1
|
@@ -33,14 +33,15 @@ Non-Negotiables
|
|
|
33
33
|
3. Version every knowledge edit by stamping an ISO date (e.g. `Updated: 2024-11-01`) near the top of the section you modify.
|
|
34
34
|
4. Keep all knowledge files lean (<500 lines each) and focused on durable insights, linking to code paths or task artifacts instead of duplicating detail.
|
|
35
35
|
5. Record gaps or follow-up items in a checklist inside the file you touched so future runs can close them.
|
|
36
|
-
6. **Semantic Indexing (MANDATORY)**: After updating any knowledge files, run the indexer to keep search current
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
6. **Semantic Indexing (MANDATORY)**: After updating any knowledge files, run the indexer to keep search current.
|
|
37
|
+
|
|
38
|
+
## Reindexing Guidance
|
|
39
|
+
|
|
40
|
+
| Scenario | Tool Argument | Rationale |
|
|
41
|
+
|----------|---------------|-----------|
|
|
42
|
+
| Routine updates | `{ "project": "{{WORKSPACE_NAME}}" }` | Incremental (fastest). Only updates changed files. |
|
|
43
|
+
| Major refactors | `{ "project": "{{WORKSPACE_NAME}}", "force": true }` | Forces re-calculation of hashes for all files without wiping. |
|
|
44
|
+
| Corrupt index / Stale vectors | `{ "project": "{{WORKSPACE_NAME}}", "clean": true }` | Wipes index files and rebuilds from scratch. Resolves vector drift. |
|
|
44
45
|
|
|
45
46
|
Deliverable
|
|
46
47
|
- 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
|
@@ -1232,8 +1232,6 @@ ${prompt.content}` : prompt.content;
|
|
|
1232
1232
|
if (fs7.existsSync(openCodeConfig)) {
|
|
1233
1233
|
const config = JSON.parse(fs7.readFileSync(openCodeConfig, "utf8"));
|
|
1234
1234
|
if (!config.agent) config.agent = {};
|
|
1235
|
-
if (!config.agent.plan) config.agent.plan = {};
|
|
1236
|
-
config.agent.plan.disable = true;
|
|
1237
1235
|
fs7.writeFileSync(openCodeConfig, JSON.stringify(config, null, 2));
|
|
1238
1236
|
}
|
|
1239
1237
|
} catch (e) {
|
|
@@ -3597,10 +3595,126 @@ var init_search = __esm({
|
|
|
3597
3595
|
}
|
|
3598
3596
|
});
|
|
3599
3597
|
|
|
3600
|
-
// src/
|
|
3598
|
+
// src/lib/drift-service.ts
|
|
3601
3599
|
import * as fs20 from "fs";
|
|
3602
3600
|
import * as path21 from "path";
|
|
3603
|
-
|
|
3601
|
+
import * as crypto2 from "crypto";
|
|
3602
|
+
var DriftService;
|
|
3603
|
+
var init_drift_service = __esm({
|
|
3604
|
+
"src/lib/drift-service.ts"() {
|
|
3605
|
+
"use strict";
|
|
3606
|
+
DriftService = class {
|
|
3607
|
+
static CHECKSUM_FILENAME = ".rrce-checksums.json";
|
|
3608
|
+
static calculateHash(filePath) {
|
|
3609
|
+
const content = fs20.readFileSync(filePath);
|
|
3610
|
+
return crypto2.createHash("md5").update(content).digest("hex");
|
|
3611
|
+
}
|
|
3612
|
+
static getManifestPath(projectPath) {
|
|
3613
|
+
return path21.join(projectPath, this.CHECKSUM_FILENAME);
|
|
3614
|
+
}
|
|
3615
|
+
static loadManifest(projectPath) {
|
|
3616
|
+
const manifestPath = this.getManifestPath(projectPath);
|
|
3617
|
+
if (!fs20.existsSync(manifestPath)) {
|
|
3618
|
+
return {};
|
|
3619
|
+
}
|
|
3620
|
+
try {
|
|
3621
|
+
return JSON.parse(fs20.readFileSync(manifestPath, "utf8"));
|
|
3622
|
+
} catch (e) {
|
|
3623
|
+
return {};
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
static saveManifest(projectPath, manifest) {
|
|
3627
|
+
const manifestPath = this.getManifestPath(projectPath);
|
|
3628
|
+
fs20.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
3629
|
+
}
|
|
3630
|
+
/**
|
|
3631
|
+
* Generates a manifest for the current state of files in the project
|
|
3632
|
+
*/
|
|
3633
|
+
static generateManifest(projectPath, files) {
|
|
3634
|
+
const manifest = {};
|
|
3635
|
+
for (const file of files) {
|
|
3636
|
+
const fullPath = path21.join(projectPath, file);
|
|
3637
|
+
if (fs20.existsSync(fullPath)) {
|
|
3638
|
+
const stats = fs20.statSync(fullPath);
|
|
3639
|
+
manifest[file] = {
|
|
3640
|
+
hash: this.calculateHash(fullPath),
|
|
3641
|
+
mtime: stats.mtimeMs
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
return manifest;
|
|
3646
|
+
}
|
|
3647
|
+
/**
|
|
3648
|
+
* Compares current files against the manifest to detect modifications and deletions
|
|
3649
|
+
*/
|
|
3650
|
+
static detectModifiedFiles(projectPath) {
|
|
3651
|
+
const manifest = this.loadManifest(projectPath);
|
|
3652
|
+
const modified = [];
|
|
3653
|
+
const deleted = [];
|
|
3654
|
+
for (const [relPath, entry] of Object.entries(manifest)) {
|
|
3655
|
+
const fullPath = path21.join(projectPath, relPath);
|
|
3656
|
+
if (!fs20.existsSync(fullPath)) {
|
|
3657
|
+
deleted.push(relPath);
|
|
3658
|
+
continue;
|
|
3659
|
+
}
|
|
3660
|
+
const stats = fs20.statSync(fullPath);
|
|
3661
|
+
if (stats.mtimeMs === entry.mtime) {
|
|
3662
|
+
continue;
|
|
3663
|
+
}
|
|
3664
|
+
const currentHash = this.calculateHash(fullPath);
|
|
3665
|
+
if (currentHash !== entry.hash) {
|
|
3666
|
+
modified.push(relPath);
|
|
3667
|
+
}
|
|
3668
|
+
}
|
|
3669
|
+
return { modified, deleted };
|
|
3670
|
+
}
|
|
3671
|
+
/**
|
|
3672
|
+
* Returns array of deleted file paths from manifest
|
|
3673
|
+
*/
|
|
3674
|
+
static detectDeletedFiles(projectPath) {
|
|
3675
|
+
const manifest = this.loadManifest(projectPath);
|
|
3676
|
+
const deleted = [];
|
|
3677
|
+
for (const relPath of Object.keys(manifest)) {
|
|
3678
|
+
const fullPath = path21.join(projectPath, relPath);
|
|
3679
|
+
if (!fs20.existsSync(fullPath)) {
|
|
3680
|
+
deleted.push(relPath);
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
return deleted;
|
|
3684
|
+
}
|
|
3685
|
+
/**
|
|
3686
|
+
* Full drift check: version + modifications
|
|
3687
|
+
*/
|
|
3688
|
+
static checkDrift(projectPath, currentVersion, runningVersion) {
|
|
3689
|
+
const { modified, deleted } = this.detectModifiedFiles(projectPath);
|
|
3690
|
+
let type = "none";
|
|
3691
|
+
let hasDrift = false;
|
|
3692
|
+
if (currentVersion !== runningVersion) {
|
|
3693
|
+
hasDrift = true;
|
|
3694
|
+
type = "version";
|
|
3695
|
+
} else if (modified.length > 0 || deleted.length > 0) {
|
|
3696
|
+
hasDrift = true;
|
|
3697
|
+
type = "modified";
|
|
3698
|
+
}
|
|
3699
|
+
return {
|
|
3700
|
+
hasDrift,
|
|
3701
|
+
type,
|
|
3702
|
+
modifiedFiles: modified,
|
|
3703
|
+
deletedFiles: deleted,
|
|
3704
|
+
version: {
|
|
3705
|
+
current: currentVersion || "0.0.0",
|
|
3706
|
+
running: runningVersion
|
|
3707
|
+
}
|
|
3708
|
+
};
|
|
3709
|
+
}
|
|
3710
|
+
};
|
|
3711
|
+
}
|
|
3712
|
+
});
|
|
3713
|
+
|
|
3714
|
+
// src/mcp/resources/indexing.ts
|
|
3715
|
+
import * as fs21 from "fs";
|
|
3716
|
+
import * as path22 from "path";
|
|
3717
|
+
async function indexKnowledge(projectName, force = false, clean = false) {
|
|
3604
3718
|
const config = loadMCPConfig();
|
|
3605
3719
|
const projects = getExposedProjects();
|
|
3606
3720
|
const project = projects.find((p2) => p2.name === projectName || p2.path && p2.path === projectName);
|
|
@@ -3629,7 +3743,7 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
3629
3743
|
};
|
|
3630
3744
|
}
|
|
3631
3745
|
const scanRoot = project.sourcePath || project.path || project.dataPath;
|
|
3632
|
-
if (!
|
|
3746
|
+
if (!fs21.existsSync(scanRoot)) {
|
|
3633
3747
|
return {
|
|
3634
3748
|
state: "failed",
|
|
3635
3749
|
status: "failed",
|
|
@@ -3642,8 +3756,14 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
3642
3756
|
}
|
|
3643
3757
|
const runIndexing = async () => {
|
|
3644
3758
|
const { shouldSkipEntryDir, shouldSkipEntryFile } = getScanContext(project, scanRoot);
|
|
3645
|
-
const
|
|
3646
|
-
const
|
|
3759
|
+
const knowledgeDir = project.knowledgePath || path22.join(scanRoot, ".rrce-workflow", "knowledge");
|
|
3760
|
+
const indexPath = path22.join(knowledgeDir, "embeddings.json");
|
|
3761
|
+
const codeIndexPath = path22.join(knowledgeDir, "code-embeddings.json");
|
|
3762
|
+
if (clean) {
|
|
3763
|
+
logger.info(`[RAG] Cleaning knowledge index for ${project.name}`);
|
|
3764
|
+
if (fs21.existsSync(indexPath)) fs21.unlinkSync(indexPath);
|
|
3765
|
+
if (fs21.existsSync(codeIndexPath)) fs21.unlinkSync(codeIndexPath);
|
|
3766
|
+
}
|
|
3647
3767
|
const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
|
|
3648
3768
|
const rag = new RAGService(indexPath, model);
|
|
3649
3769
|
const codeRag = new RAGService(codeIndexPath, model);
|
|
@@ -3653,14 +3773,14 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
3653
3773
|
let itemsTotal = 0;
|
|
3654
3774
|
let itemsDone = 0;
|
|
3655
3775
|
const preCount = (dir) => {
|
|
3656
|
-
const entries =
|
|
3776
|
+
const entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
3657
3777
|
for (const entry of entries) {
|
|
3658
|
-
const fullPath =
|
|
3778
|
+
const fullPath = path22.join(dir, entry.name);
|
|
3659
3779
|
if (entry.isDirectory()) {
|
|
3660
3780
|
if (shouldSkipEntryDir(fullPath)) continue;
|
|
3661
3781
|
preCount(fullPath);
|
|
3662
3782
|
} else if (entry.isFile()) {
|
|
3663
|
-
const ext =
|
|
3783
|
+
const ext = path22.extname(entry.name).toLowerCase();
|
|
3664
3784
|
if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
|
|
3665
3785
|
if (shouldSkipEntryFile(fullPath)) continue;
|
|
3666
3786
|
itemsTotal++;
|
|
@@ -3672,13 +3792,18 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
3672
3792
|
const cleanupIgnoredFiles = async () => {
|
|
3673
3793
|
const indexedFiles = [...rag.getIndexedFiles(), ...codeRag.getIndexedFiles()];
|
|
3674
3794
|
const unique = Array.from(new Set(indexedFiles));
|
|
3795
|
+
const deletedFiles = project.dataPath ? DriftService.detectDeletedFiles(project.dataPath) : [];
|
|
3796
|
+
if (deletedFiles.length > 0) {
|
|
3797
|
+
logger.info(`[RAG] ${project.name}: Detected ${deletedFiles.length} deleted files from manifest`);
|
|
3798
|
+
}
|
|
3675
3799
|
for (const filePath of unique) {
|
|
3676
|
-
if (!
|
|
3677
|
-
const relFilePath = filePath.split(
|
|
3678
|
-
const relScanRoot = scanRoot.split(
|
|
3800
|
+
if (!path22.isAbsolute(filePath)) continue;
|
|
3801
|
+
const relFilePath = filePath.split(path22.sep).join("/");
|
|
3802
|
+
const relScanRoot = scanRoot.split(path22.sep).join("/");
|
|
3679
3803
|
const isInScanRoot = relFilePath === relScanRoot || relFilePath.startsWith(`${relScanRoot}/`);
|
|
3680
3804
|
if (!isInScanRoot) continue;
|
|
3681
|
-
|
|
3805
|
+
const isDeleted = deletedFiles.some((df) => filePath.endsWith(df));
|
|
3806
|
+
if (shouldSkipEntryFile(filePath) || isDeleted || !fs21.existsSync(filePath)) {
|
|
3682
3807
|
await rag.removeFile(filePath);
|
|
3683
3808
|
await codeRag.removeFile(filePath);
|
|
3684
3809
|
}
|
|
@@ -3686,21 +3811,21 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
3686
3811
|
};
|
|
3687
3812
|
await cleanupIgnoredFiles();
|
|
3688
3813
|
const scanDir = async (dir) => {
|
|
3689
|
-
const entries =
|
|
3814
|
+
const entries = fs21.readdirSync(dir, { withFileTypes: true });
|
|
3690
3815
|
for (const entry of entries) {
|
|
3691
|
-
const fullPath =
|
|
3816
|
+
const fullPath = path22.join(dir, entry.name);
|
|
3692
3817
|
if (entry.isDirectory()) {
|
|
3693
3818
|
if (shouldSkipEntryDir(fullPath)) continue;
|
|
3694
3819
|
await scanDir(fullPath);
|
|
3695
3820
|
} else if (entry.isFile()) {
|
|
3696
|
-
const ext =
|
|
3821
|
+
const ext = path22.extname(entry.name).toLowerCase();
|
|
3697
3822
|
if (!INDEXABLE_EXTENSIONS.includes(ext)) continue;
|
|
3698
3823
|
if (shouldSkipEntryFile(fullPath)) continue;
|
|
3699
3824
|
try {
|
|
3700
3825
|
indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
|
|
3701
|
-
const stat =
|
|
3826
|
+
const stat = fs21.statSync(fullPath);
|
|
3702
3827
|
const mtime = force ? void 0 : stat.mtimeMs;
|
|
3703
|
-
const content =
|
|
3828
|
+
const content = fs21.readFileSync(fullPath, "utf-8");
|
|
3704
3829
|
const wasIndexed = await rag.indexFile(fullPath, content, mtime);
|
|
3705
3830
|
if (wasIndexed) {
|
|
3706
3831
|
indexed++;
|
|
@@ -3772,11 +3897,12 @@ var init_indexing = __esm({
|
|
|
3772
3897
|
init_projects();
|
|
3773
3898
|
init_utils2();
|
|
3774
3899
|
init_constants();
|
|
3900
|
+
init_drift_service();
|
|
3775
3901
|
}
|
|
3776
3902
|
});
|
|
3777
3903
|
|
|
3778
3904
|
// src/mcp/resources/context.ts
|
|
3779
|
-
import * as
|
|
3905
|
+
import * as path23 from "path";
|
|
3780
3906
|
import * as os4 from "os";
|
|
3781
3907
|
function getContextPreamble() {
|
|
3782
3908
|
const activeProject = detectActiveProject();
|
|
@@ -3792,7 +3918,7 @@ If the above tools fail, ask the user for clarification.
|
|
|
3792
3918
|
---
|
|
3793
3919
|
`;
|
|
3794
3920
|
}
|
|
3795
|
-
const rrceHome = process.env.RRCE_HOME ||
|
|
3921
|
+
const rrceHome = process.env.RRCE_HOME || path23.join(os4.homedir(), ".rrce-workflow");
|
|
3796
3922
|
const workspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
3797
3923
|
const rrceData = activeProject.dataPath;
|
|
3798
3924
|
return `## System Context
|
|
@@ -4087,8 +4213,8 @@ var init_validation = __esm({
|
|
|
4087
4213
|
});
|
|
4088
4214
|
|
|
4089
4215
|
// src/mcp/resources/sessions.ts
|
|
4090
|
-
import * as
|
|
4091
|
-
import * as
|
|
4216
|
+
import * as fs22 from "fs";
|
|
4217
|
+
import * as path24 from "path";
|
|
4092
4218
|
function startSession(projectName, taskSlug, agent, phase) {
|
|
4093
4219
|
const config = loadMCPConfig();
|
|
4094
4220
|
const projects = projectService.scan();
|
|
@@ -4096,8 +4222,8 @@ function startSession(projectName, taskSlug, agent, phase) {
|
|
|
4096
4222
|
if (!project || !project.tasksPath) {
|
|
4097
4223
|
return { success: false, message: `Project '${projectName}' not found or not exposed.` };
|
|
4098
4224
|
}
|
|
4099
|
-
const taskDir =
|
|
4100
|
-
if (!
|
|
4225
|
+
const taskDir = path24.join(project.tasksPath, taskSlug);
|
|
4226
|
+
if (!fs22.existsSync(taskDir)) {
|
|
4101
4227
|
return { success: false, message: `Task '${taskSlug}' not found.` };
|
|
4102
4228
|
}
|
|
4103
4229
|
const session = {
|
|
@@ -4107,8 +4233,8 @@ function startSession(projectName, taskSlug, agent, phase) {
|
|
|
4107
4233
|
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4108
4234
|
heartbeat: (/* @__PURE__ */ new Date()).toISOString()
|
|
4109
4235
|
};
|
|
4110
|
-
const sessionPath =
|
|
4111
|
-
|
|
4236
|
+
const sessionPath = path24.join(taskDir, "session.json");
|
|
4237
|
+
fs22.writeFileSync(sessionPath, JSON.stringify(session, null, 2));
|
|
4112
4238
|
return { success: true, message: `Session started for ${agent} agent on task '${taskSlug}' (phase: ${phase})` };
|
|
4113
4239
|
}
|
|
4114
4240
|
function endSession(projectName, taskSlug) {
|
|
@@ -4118,11 +4244,11 @@ function endSession(projectName, taskSlug) {
|
|
|
4118
4244
|
if (!project || !project.tasksPath) {
|
|
4119
4245
|
return { success: false, message: `Project '${projectName}' not found or not exposed.` };
|
|
4120
4246
|
}
|
|
4121
|
-
const sessionPath =
|
|
4122
|
-
if (!
|
|
4247
|
+
const sessionPath = path24.join(project.tasksPath, taskSlug, "session.json");
|
|
4248
|
+
if (!fs22.existsSync(sessionPath)) {
|
|
4123
4249
|
return { success: true, message: `No active session for task '${taskSlug}'.` };
|
|
4124
4250
|
}
|
|
4125
|
-
|
|
4251
|
+
fs22.unlinkSync(sessionPath);
|
|
4126
4252
|
return { success: true, message: `Session ended for task '${taskSlug}'.` };
|
|
4127
4253
|
}
|
|
4128
4254
|
function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
|
|
@@ -4132,9 +4258,9 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
|
|
|
4132
4258
|
if (!project || !project.tasksPath) {
|
|
4133
4259
|
return { success: false, message: `Project '${projectName}' not found or not exposed.` };
|
|
4134
4260
|
}
|
|
4135
|
-
const taskDir =
|
|
4136
|
-
if (!
|
|
4137
|
-
|
|
4261
|
+
const taskDir = path24.join(project.tasksPath, taskSlug);
|
|
4262
|
+
if (!fs22.existsSync(taskDir)) {
|
|
4263
|
+
fs22.mkdirSync(taskDir, { recursive: true });
|
|
4138
4264
|
}
|
|
4139
4265
|
const todos = {
|
|
4140
4266
|
phase,
|
|
@@ -4142,8 +4268,8 @@ function updateAgentTodos(projectName, taskSlug, phase, agent, items) {
|
|
|
4142
4268
|
items,
|
|
4143
4269
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4144
4270
|
};
|
|
4145
|
-
const todosPath =
|
|
4146
|
-
|
|
4271
|
+
const todosPath = path24.join(taskDir, "agent-todos.json");
|
|
4272
|
+
fs22.writeFileSync(todosPath, JSON.stringify(todos, null, 2));
|
|
4147
4273
|
return { success: true, message: `Updated ${items.length} todo items for task '${taskSlug}'.`, count: items.length };
|
|
4148
4274
|
}
|
|
4149
4275
|
var init_sessions = __esm({
|
|
@@ -4264,15 +4390,15 @@ var init_resources3 = __esm({
|
|
|
4264
4390
|
});
|
|
4265
4391
|
|
|
4266
4392
|
// src/mcp/prompts.ts
|
|
4267
|
-
import * as
|
|
4268
|
-
import * as
|
|
4393
|
+
import * as path25 from "path";
|
|
4394
|
+
import * as fs23 from "fs";
|
|
4269
4395
|
function loadBaseProtocol2() {
|
|
4270
4396
|
if (baseProtocolCache !== null) {
|
|
4271
4397
|
return baseProtocolCache;
|
|
4272
4398
|
}
|
|
4273
|
-
const basePath =
|
|
4274
|
-
if (
|
|
4275
|
-
const content =
|
|
4399
|
+
const basePath = path25.join(getAgentCorePromptsDir(), "_base.md");
|
|
4400
|
+
if (fs23.existsSync(basePath)) {
|
|
4401
|
+
const content = fs23.readFileSync(basePath, "utf-8");
|
|
4276
4402
|
baseProtocolCache = content.replace(/^---[\s\S]*?---\n*/, "");
|
|
4277
4403
|
return baseProtocolCache;
|
|
4278
4404
|
}
|
|
@@ -4335,15 +4461,15 @@ function renderPromptWithContext(content, args) {
|
|
|
4335
4461
|
resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
4336
4462
|
resolvedWorkspaceName = activeProject.name;
|
|
4337
4463
|
if (activeProject.source === "global") {
|
|
4338
|
-
const workspacesDir =
|
|
4339
|
-
resolvedRrceHome =
|
|
4464
|
+
const workspacesDir = path25.dirname(activeProject.dataPath);
|
|
4465
|
+
resolvedRrceHome = path25.dirname(workspacesDir);
|
|
4340
4466
|
}
|
|
4341
4467
|
} else {
|
|
4342
4468
|
try {
|
|
4343
4469
|
const workspaceRoot = detectWorkspaceRoot();
|
|
4344
|
-
const workspaceName =
|
|
4345
|
-
const globalWorkspacePath =
|
|
4346
|
-
if (
|
|
4470
|
+
const workspaceName = path25.basename(workspaceRoot);
|
|
4471
|
+
const globalWorkspacePath = path25.join(DEFAULT_RRCE_HOME, "workspaces", workspaceName);
|
|
4472
|
+
if (fs23.existsSync(globalWorkspacePath)) {
|
|
4347
4473
|
resolvedRrceData = globalWorkspacePath;
|
|
4348
4474
|
resolvedWorkspaceRoot = workspaceRoot;
|
|
4349
4475
|
resolvedWorkspaceName = workspaceName;
|
|
@@ -4555,7 +4681,8 @@ function registerToolHandlers(server) {
|
|
|
4555
4681
|
type: "object",
|
|
4556
4682
|
properties: {
|
|
4557
4683
|
project: { type: "string", description: "Name of the project to index" },
|
|
4558
|
-
force: { type: "boolean", description: "Force re-indexing of all files" }
|
|
4684
|
+
force: { type: "boolean", description: "Force re-indexing of all files" },
|
|
4685
|
+
clean: { type: "boolean", description: "Wipe existing index and rebuild from scratch" }
|
|
4559
4686
|
},
|
|
4560
4687
|
required: ["project"]
|
|
4561
4688
|
}
|
|
@@ -4790,7 +4917,7 @@ function registerToolHandlers(server) {
|
|
|
4790
4917
|
}
|
|
4791
4918
|
case "index_knowledge": {
|
|
4792
4919
|
const params = args;
|
|
4793
|
-
const result = await indexKnowledge(params.project, params.force);
|
|
4920
|
+
const result = await indexKnowledge(params.project, params.force, params.clean);
|
|
4794
4921
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4795
4922
|
}
|
|
4796
4923
|
case "list_projects": {
|
|
@@ -5292,105 +5419,6 @@ var init_Header = __esm({
|
|
|
5292
5419
|
}
|
|
5293
5420
|
});
|
|
5294
5421
|
|
|
5295
|
-
// src/lib/drift-service.ts
|
|
5296
|
-
import * as fs23 from "fs";
|
|
5297
|
-
import * as path25 from "path";
|
|
5298
|
-
import * as crypto2 from "crypto";
|
|
5299
|
-
var DriftService;
|
|
5300
|
-
var init_drift_service = __esm({
|
|
5301
|
-
"src/lib/drift-service.ts"() {
|
|
5302
|
-
"use strict";
|
|
5303
|
-
DriftService = class {
|
|
5304
|
-
static CHECKSUM_FILENAME = ".rrce-checksums.json";
|
|
5305
|
-
static calculateHash(filePath) {
|
|
5306
|
-
const content = fs23.readFileSync(filePath);
|
|
5307
|
-
return crypto2.createHash("md5").update(content).digest("hex");
|
|
5308
|
-
}
|
|
5309
|
-
static getManifestPath(projectPath) {
|
|
5310
|
-
return path25.join(projectPath, this.CHECKSUM_FILENAME);
|
|
5311
|
-
}
|
|
5312
|
-
static loadManifest(projectPath) {
|
|
5313
|
-
const manifestPath = this.getManifestPath(projectPath);
|
|
5314
|
-
if (!fs23.existsSync(manifestPath)) {
|
|
5315
|
-
return {};
|
|
5316
|
-
}
|
|
5317
|
-
try {
|
|
5318
|
-
return JSON.parse(fs23.readFileSync(manifestPath, "utf8"));
|
|
5319
|
-
} catch (e) {
|
|
5320
|
-
return {};
|
|
5321
|
-
}
|
|
5322
|
-
}
|
|
5323
|
-
static saveManifest(projectPath, manifest) {
|
|
5324
|
-
const manifestPath = this.getManifestPath(projectPath);
|
|
5325
|
-
fs23.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
5326
|
-
}
|
|
5327
|
-
/**
|
|
5328
|
-
* Generates a manifest for the current state of files in the project
|
|
5329
|
-
*/
|
|
5330
|
-
static generateManifest(projectPath, files) {
|
|
5331
|
-
const manifest = {};
|
|
5332
|
-
for (const file of files) {
|
|
5333
|
-
const fullPath = path25.join(projectPath, file);
|
|
5334
|
-
if (fs23.existsSync(fullPath)) {
|
|
5335
|
-
const stats = fs23.statSync(fullPath);
|
|
5336
|
-
manifest[file] = {
|
|
5337
|
-
hash: this.calculateHash(fullPath),
|
|
5338
|
-
mtime: stats.mtimeMs
|
|
5339
|
-
};
|
|
5340
|
-
}
|
|
5341
|
-
}
|
|
5342
|
-
return manifest;
|
|
5343
|
-
}
|
|
5344
|
-
/**
|
|
5345
|
-
* Compares current files against the manifest to detect modifications
|
|
5346
|
-
*/
|
|
5347
|
-
static detectModifiedFiles(projectPath) {
|
|
5348
|
-
const manifest = this.loadManifest(projectPath);
|
|
5349
|
-
const modifiedFiles = [];
|
|
5350
|
-
for (const [relPath, entry] of Object.entries(manifest)) {
|
|
5351
|
-
const fullPath = path25.join(projectPath, relPath);
|
|
5352
|
-
if (!fs23.existsSync(fullPath)) {
|
|
5353
|
-
continue;
|
|
5354
|
-
}
|
|
5355
|
-
const stats = fs23.statSync(fullPath);
|
|
5356
|
-
if (stats.mtimeMs === entry.mtime) {
|
|
5357
|
-
continue;
|
|
5358
|
-
}
|
|
5359
|
-
const currentHash = this.calculateHash(fullPath);
|
|
5360
|
-
if (currentHash !== entry.hash) {
|
|
5361
|
-
modifiedFiles.push(relPath);
|
|
5362
|
-
}
|
|
5363
|
-
}
|
|
5364
|
-
return modifiedFiles;
|
|
5365
|
-
}
|
|
5366
|
-
/**
|
|
5367
|
-
* Full drift check: version + modifications
|
|
5368
|
-
*/
|
|
5369
|
-
static checkDrift(projectPath, currentVersion, runningVersion) {
|
|
5370
|
-
const modifiedFiles = this.detectModifiedFiles(projectPath);
|
|
5371
|
-
let type = "none";
|
|
5372
|
-
let hasDrift = false;
|
|
5373
|
-
if (currentVersion !== runningVersion) {
|
|
5374
|
-
hasDrift = true;
|
|
5375
|
-
type = "version";
|
|
5376
|
-
} else if (modifiedFiles.length > 0) {
|
|
5377
|
-
hasDrift = true;
|
|
5378
|
-
type = "modified";
|
|
5379
|
-
}
|
|
5380
|
-
return {
|
|
5381
|
-
hasDrift,
|
|
5382
|
-
type,
|
|
5383
|
-
modifiedFiles,
|
|
5384
|
-
version: {
|
|
5385
|
-
current: currentVersion || "0.0.0",
|
|
5386
|
-
running: runningVersion
|
|
5387
|
-
}
|
|
5388
|
-
};
|
|
5389
|
-
}
|
|
5390
|
-
};
|
|
5391
|
-
}
|
|
5392
|
-
});
|
|
5393
|
-
|
|
5394
5422
|
// src/mcp/ui/ConfigContext.tsx
|
|
5395
5423
|
var ConfigContext_exports = {};
|
|
5396
5424
|
__export(ConfigContext_exports, {
|