rrce-workflow 0.2.63 → 0.2.65
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 +5 -2
- package/agent-core/prompts/doctor.md +13 -7
- package/agent-core/prompts/documentation.md +12 -15
- package/agent-core/prompts/executor.md +12 -15
- package/agent-core/prompts/init.md +16 -25
- package/agent-core/prompts/planning_orchestrator.md +12 -15
- package/agent-core/prompts/research_discussion.md +12 -15
- package/agent-core/prompts/sync.md +12 -15
- package/dist/index.js +231 -161
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,11 +98,13 @@ Add to `~/.config/claude/claude_desktop_config.json`:
|
|
|
98
98
|
RRCE-Workflow supports two ways to store your agent workflow data (`knowledge/`, `tasks/`, `refs/`).
|
|
99
99
|
|
|
100
100
|
### 1. Global Mode (Default & Recommended)
|
|
101
|
-
Stores configuration and knowledge outside your project directory in `~/.rrce-workflow/workspaces/<project-name
|
|
101
|
+
Stores configuration and knowledge outside your project directory in `~/.rrce-workflow/workspaces/<project-name>` (or a custom path you configure).
|
|
102
102
|
|
|
103
103
|
* **✅ Pros**: Keeps your repo clean, easy cross-project linking, no `.gitignore` pollution.
|
|
104
104
|
* **❌ Cons**: Knowledge isn't checked into your project's git repo (unless you manually sync/backup).
|
|
105
105
|
|
|
106
|
+
**Custom Global Path**: When running the wizard, you can choose a custom location instead of `~/.rrce-workflow/`. Your preference is saved and automatically used for future projects.
|
|
107
|
+
|
|
106
108
|
### 2. Workspace Mode (Alternative)
|
|
107
109
|
Stores everything in a `.rrce-workflow` folder inside your project root.
|
|
108
110
|
|
|
@@ -125,6 +127,7 @@ Once installed, you gain access to powerful agent workflows. Invoke them using y
|
|
|
125
127
|
| **Execute** | **Implementation** | The "coding" phase. Implements the plan created by the Planning agent. |
|
|
126
128
|
| **Docs** | **Documentation** | Generates tailored docs (API refs, guides) from code. |
|
|
127
129
|
| **Sync** | **Knowledge Maintenance** | Scans code changes to update the `knowledge/` folder. |
|
|
130
|
+
| **Doctor** | **Health Analysis** | Analyzes codebase for issues, tech debt, and improvement opportunities. |
|
|
128
131
|
|
|
129
132
|
### Recommended Workflow
|
|
130
133
|
1. **`/init`**: "Analyze this codebase." -> Creates `project-context.md`.
|
|
@@ -145,7 +148,7 @@ RAG is enabled by default in Express Setup. You can toggle it per-project in the
|
|
|
145
148
|
|
|
146
149
|
---
|
|
147
150
|
|
|
148
|
-
##
|
|
151
|
+
## Requirements
|
|
149
152
|
|
|
150
153
|
- **Node.js 18+**
|
|
151
154
|
- **Git**
|
|
@@ -18,13 +18,19 @@ auto-identity:
|
|
|
18
18
|
|
|
19
19
|
You are the Project Doctor for RRCE-Workflow. Operate like a senior technical consultant performing a health check on the codebase to identify issues, technical debt, and improvement opportunities.
|
|
20
20
|
|
|
21
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
RRCE_HOME =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
22
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
23
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
24
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
25
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
26
|
+
|
|
27
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config.
|
|
28
|
+
|
|
29
|
+
Path Variables Reference:
|
|
30
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
31
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
32
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
33
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
28
34
|
|
|
29
35
|
## Pipeline Position
|
|
30
36
|
- **Input**: Can be triggered at any time for project health analysis.
|
|
@@ -20,13 +20,13 @@ auto-identity:
|
|
|
20
20
|
|
|
21
21
|
You are the Documentation Lead for the project. Operate like a senior engineering manager responsible for synthesizing knowledge and preparing smooth handovers.
|
|
22
22
|
|
|
23
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
RRCE_HOME =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
24
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
25
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
26
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
27
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
28
|
+
|
|
29
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config.
|
|
30
30
|
|
|
31
31
|
Pipeline Position
|
|
32
32
|
- **Optional**: Documentation can be run at any point, but is most valuable after Execution.
|
|
@@ -55,14 +55,11 @@ Non-Negotiables
|
|
|
55
55
|
5. Store persistent insights back into `{{RRCE_DATA}}/knowledge` when they apply beyond the immediate deliverable.
|
|
56
56
|
6. Close the loop in `meta.json` when working within a task by setting `agents.documentation.status`, refreshing `checklist`, and updating overall `status`.
|
|
57
57
|
|
|
58
|
-
Path
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
2. Resolve: `workspace` → `.rrce-workflow/` | `global` → `{{RRCE_HOME}}/workspaces/<name>/`
|
|
64
|
-
|
|
65
|
-
**How to resolve `{{RRCE_HOME}}`**: `config.yaml` → `storage.globalPath` or default `~/.rrce-workflow`
|
|
58
|
+
Path Variables Reference
|
|
59
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
60
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
61
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
62
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
66
63
|
|
|
67
64
|
Cross-Project References
|
|
68
65
|
- Reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project>/knowledge/`
|
|
@@ -16,13 +16,13 @@ auto-identity:
|
|
|
16
16
|
|
|
17
17
|
You are the Executor for the project. Operate like a senior individual contributor who ships clean, well-tested code aligned with the orchestrated plan.
|
|
18
18
|
|
|
19
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
RRCE_HOME =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
20
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
21
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
22
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
23
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
24
|
+
|
|
25
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config.
|
|
26
26
|
|
|
27
27
|
Pipeline Position
|
|
28
28
|
- **Requires**: Planning phase must be complete before execution can begin.
|
|
@@ -60,14 +60,11 @@ Non-Negotiables
|
|
|
60
60
|
5. Keep execution notes under 500 lines, logging command outputs succinctly rather than verbatim dumps.
|
|
61
61
|
6. Update `meta.json` as you proceed so statuses stay accurate.
|
|
62
62
|
|
|
63
|
-
Path
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
2. Resolve: `workspace` → `.rrce-workflow/` | `global` → `{{RRCE_HOME}}/workspaces/<name>/`
|
|
69
|
-
|
|
70
|
-
**How to resolve `{{RRCE_HOME}}`**: `config.yaml` → `storage.globalPath` or default `~/.rrce-workflow`
|
|
63
|
+
Path Variables Reference
|
|
64
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
65
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
66
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
67
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
71
68
|
|
|
72
69
|
Cross-Project References
|
|
73
70
|
- Reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project>/knowledge/`
|
|
@@ -15,13 +15,16 @@ auto-identity:
|
|
|
15
15
|
|
|
16
16
|
You are the Project Initializer for RRCE-Workflow. Operate like a senior architect performing a comprehensive codebase audit to establish foundational context for all downstream agents.
|
|
17
17
|
|
|
18
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
RRCE_HOME =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
19
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
20
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
21
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
22
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
23
|
+
|
|
24
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config:
|
|
25
|
+
1. Check `.rrce-workflow/config.yaml` (workspace mode) OR `{{RRCE_HOME}}/workspaces/<project>/config.yaml` (global mode)
|
|
26
|
+
2. Resolve: `RRCE_DATA = (mode == "workspace") ? ".rrce-workflow/" : "${RRCE_HOME}/workspaces/${project.name}/"`
|
|
27
|
+
3. Default if no config: `RRCE_HOME=~/.rrce-workflow`, `RRCE_DATA=.rrce-workflow/`
|
|
25
28
|
|
|
26
29
|
Pipeline Position
|
|
27
30
|
- **Entry Point**: Init can be run at any time to establish or update project context.
|
|
@@ -41,29 +44,17 @@ Non-Negotiables
|
|
|
41
44
|
5. Never assume; if information is ambiguous, note it as requiring clarification.
|
|
42
45
|
6. Keep output actionable and scannable; use structured sections.
|
|
43
46
|
|
|
44
|
-
Path
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
2. Get `storage.mode` (default: `global`) and `project.name`
|
|
50
|
-
3. Resolve based on mode:
|
|
51
|
-
- `workspace` → `<workspace>/.rrce-workflow/`
|
|
52
|
-
- `global` → `{{RRCE_HOME}}/workspaces/<project.name>/`
|
|
53
|
-
|
|
54
|
-
**How to resolve `{{RRCE_HOME}}`** (global home):
|
|
55
|
-
1. Read `.rrce-workflow/config.yaml`
|
|
56
|
-
2. If `storage.globalPath` exists, use that value
|
|
57
|
-
3. Otherwise, default to `~/.rrce-workflow`
|
|
58
|
-
|
|
59
|
-
**Other variables:**
|
|
60
|
-
- `{{WORKSPACE_ROOT}}` = Current workspace directory
|
|
61
|
-
- `{{WORKSPACE_NAME}}` = `config.yaml` → `project.name`
|
|
47
|
+
Path Variables Reference
|
|
48
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
49
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
50
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
51
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
62
52
|
|
|
63
53
|
Cross-Project References
|
|
64
54
|
- To reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project-name>/knowledge/`
|
|
65
55
|
- Example: FE project can reference BE project via `{{RRCE_HOME}}/workspaces/my-backend/knowledge/project-context.md`
|
|
66
56
|
|
|
57
|
+
|
|
67
58
|
Discovery Workflow
|
|
68
59
|
1. **Project Identity**
|
|
69
60
|
- Detect project name from manifests or directory name
|
|
@@ -13,13 +13,13 @@ auto-identity:
|
|
|
13
13
|
|
|
14
14
|
You are the Planning & Task Orchestrator for the project. Operate like an engineering manager with deep scoped knowledge of this codebase.
|
|
15
15
|
|
|
16
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
RRCE_HOME =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
17
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
18
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
19
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
20
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
21
|
+
|
|
22
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config.
|
|
23
23
|
|
|
24
24
|
Pipeline Position
|
|
25
25
|
- **Requires**: Research phase must be complete before planning can begin.
|
|
@@ -52,14 +52,11 @@ Non-Negotiables
|
|
|
52
52
|
5. Track how each task ties back to product goals, risks, and testing strategy.
|
|
53
53
|
6. Keep the written plan under 500 lines and reference supporting materials explicitly.
|
|
54
54
|
|
|
55
|
-
Path
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
2. Resolve: `workspace` → `.rrce-workflow/` | `global` → `{{RRCE_HOME}}/workspaces/<name>/`
|
|
61
|
-
|
|
62
|
-
**How to resolve `{{RRCE_HOME}}`**: `config.yaml` → `storage.globalPath` or default `~/.rrce-workflow`
|
|
55
|
+
Path Variables Reference
|
|
56
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
57
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
58
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
59
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
63
60
|
|
|
64
61
|
Cross-Project References
|
|
65
62
|
- Reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project>/knowledge/`
|
|
@@ -20,13 +20,13 @@ auto-identity:
|
|
|
20
20
|
|
|
21
21
|
You are the Research & Discussion Lead for the project. Operate like a staff-level tech lead who owns broad project awareness.
|
|
22
22
|
|
|
23
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
RRCE_HOME =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
24
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
25
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
26
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
27
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
28
|
+
|
|
29
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config.
|
|
30
30
|
|
|
31
31
|
Pipeline Position
|
|
32
32
|
- **Entry Point**: Research can be the first agent invoked for a new task.
|
|
@@ -45,14 +45,11 @@ Non-Negotiables
|
|
|
45
45
|
5. Do not hand off to Planning until answers are captured or explicitly marked as pending for follow-up.
|
|
46
46
|
6. Keep the final brief under 500 lines and reference concrete sources whenever possible.
|
|
47
47
|
|
|
48
|
-
Path
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
2. Resolve: `workspace` → `.rrce-workflow/` | `global` → `{{RRCE_HOME}}/workspaces/<name>/`
|
|
54
|
-
|
|
55
|
-
**How to resolve `{{RRCE_HOME}}`**: `config.yaml` → `storage.globalPath` or default `~/.rrce-workflow`
|
|
48
|
+
Path Variables Reference
|
|
49
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
50
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
51
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
52
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
56
53
|
|
|
57
54
|
Cross-Project References
|
|
58
55
|
- Reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project>/knowledge/`
|
|
@@ -14,13 +14,13 @@ auto-identity:
|
|
|
14
14
|
|
|
15
15
|
You are the Knowledge Sync Lead. Act like a senior architect charged with keeping the RRCE knowledge cache authoritative and current.
|
|
16
16
|
|
|
17
|
-
**⚠️ FIRST STEP (MANDATORY)**
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
RRCE_HOME =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
**⚠️ FIRST STEP (MANDATORY) - Path Resolution**
|
|
18
|
+
Check if the system has pre-resolved paths for you. Look for a "System Resolved Paths" section at the start of this prompt context. If present, use those values directly:
|
|
19
|
+
- `RRCE_DATA` = Pre-resolved data path (where knowledge, tasks, refs are stored)
|
|
20
|
+
- `RRCE_HOME` = Pre-resolved global home
|
|
21
|
+
- `WORKSPACE_ROOT` = Pre-resolved source code location
|
|
22
|
+
|
|
23
|
+
**Only if no pre-resolved paths are present**, fall back to manual resolution by reading config.
|
|
24
24
|
|
|
25
25
|
Pipeline Position
|
|
26
26
|
- **Maintenance Agent**: Sync runs periodically or after significant codebase changes to keep knowledge current.
|
|
@@ -45,14 +45,11 @@ Non-Negotiables
|
|
|
45
45
|
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.
|
|
46
46
|
5. Record gaps or follow-up items in a checklist inside the file you touched so future runs can close them.
|
|
47
47
|
|
|
48
|
-
Path
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
2. Resolve: `workspace` → `.rrce-workflow/` | `global` → `{{RRCE_HOME}}/workspaces/<name>/`
|
|
54
|
-
|
|
55
|
-
**How to resolve `{{RRCE_HOME}}`**: `config.yaml` → `storage.globalPath` or default `~/.rrce-workflow`
|
|
48
|
+
Path Variables Reference
|
|
49
|
+
- `{{RRCE_DATA}}` = Primary data path (knowledge, tasks, refs storage)
|
|
50
|
+
- `{{RRCE_HOME}}` = Global RRCE home directory
|
|
51
|
+
- `{{WORKSPACE_ROOT}}` = Source code directory
|
|
52
|
+
- `{{WORKSPACE_NAME}}` = Project name
|
|
56
53
|
|
|
57
54
|
Cross-Project References
|
|
58
55
|
- Reference another project's context: `{{RRCE_HOME}}/workspaces/<other-project>/knowledge/`
|
package/dist/index.js
CHANGED
|
@@ -24,46 +24,86 @@ var init_git = __esm({
|
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
// src/lib/
|
|
27
|
+
// src/lib/preferences.ts
|
|
28
28
|
import * as fs from "fs";
|
|
29
29
|
import * as path from "path";
|
|
30
|
+
function getPreferencesPath() {
|
|
31
|
+
const home = process.env.HOME || "~";
|
|
32
|
+
return path.join(home, ".rrce-workflow", "preferences.json");
|
|
33
|
+
}
|
|
34
|
+
function loadUserPreferences() {
|
|
35
|
+
const prefPath = getPreferencesPath();
|
|
36
|
+
if (!fs.existsSync(prefPath)) {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(fs.readFileSync(prefPath, "utf-8"));
|
|
41
|
+
} catch {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function saveUserPreferences(prefs) {
|
|
46
|
+
const prefPath = getPreferencesPath();
|
|
47
|
+
ensureDir(path.dirname(prefPath));
|
|
48
|
+
const current = loadUserPreferences();
|
|
49
|
+
const refined = { ...current, ...prefs };
|
|
50
|
+
fs.writeFileSync(prefPath, JSON.stringify(refined, null, 2));
|
|
51
|
+
}
|
|
52
|
+
var init_preferences = __esm({
|
|
53
|
+
"src/lib/preferences.ts"() {
|
|
54
|
+
"use strict";
|
|
55
|
+
init_paths();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// src/lib/paths.ts
|
|
60
|
+
import * as fs2 from "fs";
|
|
61
|
+
import * as path2 from "path";
|
|
62
|
+
function getEffectiveGlobalPath() {
|
|
63
|
+
const prefs = loadUserPreferences();
|
|
64
|
+
if (prefs.useCustomGlobalPath && prefs.defaultGlobalPath) {
|
|
65
|
+
return prefs.defaultGlobalPath;
|
|
66
|
+
}
|
|
67
|
+
return RRCE_HOME;
|
|
68
|
+
}
|
|
30
69
|
function detectWorkspaceRoot() {
|
|
31
70
|
if (RRCE_WORKSPACE) {
|
|
32
71
|
return RRCE_WORKSPACE;
|
|
33
72
|
}
|
|
34
73
|
let current = process.cwd();
|
|
35
74
|
while (current !== "/") {
|
|
36
|
-
if (
|
|
75
|
+
if (fs2.existsSync(path2.join(current, ".git")) || fs2.existsSync(path2.join(current, ".rrce-workflow", "config.yaml")) || fs2.existsSync(path2.join(current, ".rrce-workflow.yaml"))) {
|
|
37
76
|
return current;
|
|
38
77
|
}
|
|
39
|
-
current =
|
|
78
|
+
current = path2.dirname(current);
|
|
40
79
|
}
|
|
41
80
|
return process.cwd();
|
|
42
81
|
}
|
|
43
82
|
function getConfigPath(workspaceRoot) {
|
|
44
|
-
const newPath =
|
|
45
|
-
const legacyPath =
|
|
46
|
-
if (
|
|
83
|
+
const newPath = path2.join(workspaceRoot, ".rrce-workflow", "config.yaml");
|
|
84
|
+
const legacyPath = path2.join(workspaceRoot, ".rrce-workflow.yaml");
|
|
85
|
+
if (fs2.existsSync(newPath)) {
|
|
47
86
|
return newPath;
|
|
48
87
|
}
|
|
49
|
-
if (
|
|
88
|
+
if (fs2.existsSync(legacyPath)) {
|
|
50
89
|
return legacyPath;
|
|
51
90
|
}
|
|
52
91
|
try {
|
|
53
|
-
const rrceHome =
|
|
54
|
-
const mcpConfigPath =
|
|
55
|
-
if (
|
|
56
|
-
const mcpContent =
|
|
92
|
+
const rrceHome = getDefaultRRCEHome2();
|
|
93
|
+
const mcpConfigPath = path2.join(rrceHome, "mcp.yaml");
|
|
94
|
+
if (fs2.existsSync(mcpConfigPath)) {
|
|
95
|
+
const mcpContent = fs2.readFileSync(mcpConfigPath, "utf-8");
|
|
57
96
|
const lines = mcpContent.split("\n");
|
|
58
97
|
let currentName = "";
|
|
59
98
|
for (let i = 0; i < lines.length; i++) {
|
|
60
|
-
const line = lines[i]
|
|
99
|
+
const line = lines[i]?.trim();
|
|
100
|
+
if (!line) continue;
|
|
61
101
|
if (line.startsWith("- name:")) {
|
|
62
102
|
currentName = line.replace("- name:", "").trim();
|
|
63
103
|
} else if (line.startsWith("path:")) {
|
|
64
104
|
const p = line.replace("path:", "").trim();
|
|
65
105
|
if (p === workspaceRoot || p === `"${workspaceRoot}"` || p === `'${workspaceRoot}'`) {
|
|
66
|
-
return
|
|
106
|
+
return path2.join(rrceHome, "workspaces", currentName, "config.yaml");
|
|
67
107
|
}
|
|
68
108
|
}
|
|
69
109
|
}
|
|
@@ -73,42 +113,42 @@ function getConfigPath(workspaceRoot) {
|
|
|
73
113
|
return newPath;
|
|
74
114
|
}
|
|
75
115
|
function getWorkspaceName(workspaceRoot) {
|
|
76
|
-
return
|
|
116
|
+
return path2.basename(workspaceRoot);
|
|
77
117
|
}
|
|
78
118
|
function getRRCEHome() {
|
|
79
119
|
return RRCE_HOME;
|
|
80
120
|
}
|
|
81
121
|
function getLocalWorkspacePath(workspaceRoot) {
|
|
82
|
-
return
|
|
122
|
+
return path2.join(workspaceRoot, ".rrce-workflow");
|
|
83
123
|
}
|
|
84
124
|
function ensureDir(dirPath) {
|
|
85
|
-
if (!
|
|
86
|
-
|
|
125
|
+
if (!fs2.existsSync(dirPath)) {
|
|
126
|
+
fs2.mkdirSync(dirPath, { recursive: true });
|
|
87
127
|
}
|
|
88
128
|
}
|
|
89
129
|
function getAgentPromptPath(workspaceRoot, tool) {
|
|
90
130
|
if (tool === "copilot") {
|
|
91
|
-
return
|
|
131
|
+
return path2.join(workspaceRoot, ".github", "agents");
|
|
92
132
|
} else {
|
|
93
|
-
return
|
|
133
|
+
return path2.join(workspaceRoot, ".agent", "workflows");
|
|
94
134
|
}
|
|
95
135
|
}
|
|
96
136
|
function copyToAllStoragePaths(sourceFile, relativePath, dataPaths) {
|
|
97
|
-
const content =
|
|
137
|
+
const content = fs2.readFileSync(sourceFile);
|
|
98
138
|
for (const dataPath of dataPaths) {
|
|
99
|
-
const targetPath =
|
|
100
|
-
ensureDir(
|
|
101
|
-
|
|
139
|
+
const targetPath = path2.join(dataPath, relativePath);
|
|
140
|
+
ensureDir(path2.dirname(targetPath));
|
|
141
|
+
fs2.writeFileSync(targetPath, content);
|
|
102
142
|
}
|
|
103
143
|
}
|
|
104
144
|
function copyDirToAllStoragePaths(sourceDir, relativeDir, dataPaths) {
|
|
105
|
-
if (!
|
|
145
|
+
if (!fs2.existsSync(sourceDir)) {
|
|
106
146
|
return;
|
|
107
147
|
}
|
|
108
|
-
const entries =
|
|
148
|
+
const entries = fs2.readdirSync(sourceDir, { withFileTypes: true });
|
|
109
149
|
for (const entry of entries) {
|
|
110
|
-
const sourcePath =
|
|
111
|
-
const relativePath =
|
|
150
|
+
const sourcePath = path2.join(sourceDir, entry.name);
|
|
151
|
+
const relativePath = path2.join(relativeDir, entry.name);
|
|
112
152
|
if (entry.isDirectory()) {
|
|
113
153
|
copyDirToAllStoragePaths(sourcePath, relativePath, dataPaths);
|
|
114
154
|
} else {
|
|
@@ -119,38 +159,38 @@ function copyDirToAllStoragePaths(sourceDir, relativeDir, dataPaths) {
|
|
|
119
159
|
function syncMetadataToAll(agentCorePath, dataPaths) {
|
|
120
160
|
const metadataDirs = ["knowledge", "refs", "tasks"];
|
|
121
161
|
for (const dir of metadataDirs) {
|
|
122
|
-
const sourceDir =
|
|
162
|
+
const sourceDir = path2.join(agentCorePath, dir);
|
|
123
163
|
copyDirToAllStoragePaths(sourceDir, dir, dataPaths);
|
|
124
164
|
}
|
|
125
165
|
}
|
|
126
166
|
function checkWriteAccess(dirPath) {
|
|
127
|
-
const testFile =
|
|
167
|
+
const testFile = path2.join(dirPath, ".rrce-write-test");
|
|
128
168
|
try {
|
|
129
|
-
if (!
|
|
130
|
-
|
|
169
|
+
if (!fs2.existsSync(dirPath)) {
|
|
170
|
+
fs2.mkdirSync(dirPath, { recursive: true });
|
|
131
171
|
}
|
|
132
|
-
|
|
133
|
-
|
|
172
|
+
fs2.writeFileSync(testFile, "write-test");
|
|
173
|
+
fs2.unlinkSync(testFile);
|
|
134
174
|
return true;
|
|
135
175
|
} catch {
|
|
136
176
|
try {
|
|
137
|
-
if (
|
|
138
|
-
|
|
177
|
+
if (fs2.existsSync(testFile)) {
|
|
178
|
+
fs2.unlinkSync(testFile);
|
|
139
179
|
}
|
|
140
180
|
} catch {
|
|
141
181
|
}
|
|
142
182
|
return false;
|
|
143
183
|
}
|
|
144
184
|
}
|
|
145
|
-
function
|
|
146
|
-
return process.env.RRCE_HOME ||
|
|
185
|
+
function getDefaultRRCEHome2() {
|
|
186
|
+
return process.env.RRCE_HOME || path2.join(process.env.HOME || "~", ".rrce-workflow");
|
|
147
187
|
}
|
|
148
188
|
function getEffectiveRRCEHome(workspaceRoot) {
|
|
149
189
|
if (workspaceRoot) {
|
|
150
190
|
const configPath = getConfigPath(workspaceRoot);
|
|
151
|
-
if (
|
|
191
|
+
if (fs2.existsSync(configPath)) {
|
|
152
192
|
try {
|
|
153
|
-
const content =
|
|
193
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
154
194
|
const globalPathMatch = content.match(/globalPath:\s*["']?([^"'\n]+)["']?/);
|
|
155
195
|
if (globalPathMatch?.[1]) {
|
|
156
196
|
return globalPathMatch[1].trim();
|
|
@@ -159,24 +199,34 @@ function getEffectiveRRCEHome(workspaceRoot) {
|
|
|
159
199
|
}
|
|
160
200
|
}
|
|
161
201
|
}
|
|
162
|
-
return
|
|
202
|
+
return getDefaultRRCEHome2();
|
|
163
203
|
}
|
|
164
204
|
var RRCE_HOME, RRCE_WORKSPACE;
|
|
165
205
|
var init_paths = __esm({
|
|
166
206
|
"src/lib/paths.ts"() {
|
|
167
207
|
"use strict";
|
|
168
|
-
|
|
208
|
+
init_preferences();
|
|
209
|
+
RRCE_HOME = process.env.RRCE_HOME || path2.join(process.env.HOME || "~", ".rrce-workflow");
|
|
169
210
|
RRCE_WORKSPACE = process.env.RRCE_WORKSPACE;
|
|
170
211
|
}
|
|
171
212
|
});
|
|
172
213
|
|
|
173
214
|
// src/lib/detection.ts
|
|
174
|
-
import * as
|
|
175
|
-
import * as
|
|
215
|
+
import * as fs3 from "fs";
|
|
216
|
+
import * as path3 from "path";
|
|
176
217
|
function scanForProjects(options = {}) {
|
|
177
|
-
const { excludeWorkspace, workspacePath } = options;
|
|
218
|
+
const { excludeWorkspace, workspacePath, knownPaths } = options;
|
|
178
219
|
const projects = [];
|
|
179
220
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
221
|
+
if (knownPaths && knownPaths.length > 0) {
|
|
222
|
+
const explicitProjects = scanKnownPaths(knownPaths, excludeWorkspace);
|
|
223
|
+
for (const project of explicitProjects) {
|
|
224
|
+
if (!seenPaths.has(project.dataPath)) {
|
|
225
|
+
seenPaths.add(project.dataPath);
|
|
226
|
+
projects.push(project);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
180
230
|
const globalProjects = scanGlobalStorage(excludeWorkspace);
|
|
181
231
|
for (const project of globalProjects) {
|
|
182
232
|
if (!seenPaths.has(project.dataPath)) {
|
|
@@ -193,23 +243,54 @@ function scanForProjects(options = {}) {
|
|
|
193
243
|
}
|
|
194
244
|
return projects;
|
|
195
245
|
}
|
|
246
|
+
function scanKnownPaths(paths, excludeWorkspace) {
|
|
247
|
+
const projects = [];
|
|
248
|
+
for (const p of paths) {
|
|
249
|
+
try {
|
|
250
|
+
if (!fs3.existsSync(p)) continue;
|
|
251
|
+
const localConfigPath = path3.join(p, ".rrce-workflow", "config.yaml");
|
|
252
|
+
if (fs3.existsSync(localConfigPath)) {
|
|
253
|
+
const config = parseWorkspaceConfig(localConfigPath);
|
|
254
|
+
if (config?.name === excludeWorkspace) continue;
|
|
255
|
+
const fullPath = path3.join(p, ".rrce-workflow");
|
|
256
|
+
const knowledgePath = path3.join(fullPath, "knowledge");
|
|
257
|
+
const refsPath = path3.join(fullPath, "refs");
|
|
258
|
+
const tasksPath = path3.join(fullPath, "tasks");
|
|
259
|
+
projects.push({
|
|
260
|
+
name: config?.name || path3.basename(p),
|
|
261
|
+
path: p,
|
|
262
|
+
dataPath: fullPath,
|
|
263
|
+
source: "local",
|
|
264
|
+
storageMode: config?.storageMode,
|
|
265
|
+
knowledgePath: fs3.existsSync(knowledgePath) ? knowledgePath : void 0,
|
|
266
|
+
refsPath: fs3.existsSync(refsPath) ? refsPath : void 0,
|
|
267
|
+
tasksPath: fs3.existsSync(tasksPath) ? tasksPath : void 0,
|
|
268
|
+
semanticSearchEnabled: config?.semanticSearchEnabled
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return projects;
|
|
276
|
+
}
|
|
196
277
|
function scanGlobalStorage(excludeWorkspace) {
|
|
197
|
-
const rrceHome =
|
|
198
|
-
const workspacesDir =
|
|
278
|
+
const rrceHome = getEffectiveGlobalPath();
|
|
279
|
+
const workspacesDir = path3.join(rrceHome, "workspaces");
|
|
199
280
|
const projects = [];
|
|
200
|
-
if (!
|
|
281
|
+
if (!fs3.existsSync(workspacesDir)) {
|
|
201
282
|
return projects;
|
|
202
283
|
}
|
|
203
284
|
try {
|
|
204
|
-
const entries =
|
|
285
|
+
const entries = fs3.readdirSync(workspacesDir, { withFileTypes: true });
|
|
205
286
|
for (const entry of entries) {
|
|
206
287
|
if (!entry.isDirectory()) continue;
|
|
207
288
|
if (entry.name === excludeWorkspace) continue;
|
|
208
|
-
const projectDataPath =
|
|
209
|
-
const knowledgePath =
|
|
210
|
-
const refsPath =
|
|
211
|
-
const tasksPath =
|
|
212
|
-
const configPath =
|
|
289
|
+
const projectDataPath = path3.join(workspacesDir, entry.name);
|
|
290
|
+
const knowledgePath = path3.join(projectDataPath, "knowledge");
|
|
291
|
+
const refsPath = path3.join(projectDataPath, "refs");
|
|
292
|
+
const tasksPath = path3.join(projectDataPath, "tasks");
|
|
293
|
+
const configPath = path3.join(projectDataPath, "config.yaml");
|
|
213
294
|
const config = parseWorkspaceConfig(configPath);
|
|
214
295
|
projects.push({
|
|
215
296
|
name: config?.name || entry.name,
|
|
@@ -219,9 +300,9 @@ function scanGlobalStorage(excludeWorkspace) {
|
|
|
219
300
|
// ...expose sourcePath if available
|
|
220
301
|
dataPath: projectDataPath,
|
|
221
302
|
source: "global",
|
|
222
|
-
knowledgePath:
|
|
223
|
-
refsPath:
|
|
224
|
-
tasksPath:
|
|
303
|
+
knowledgePath: fs3.existsSync(knowledgePath) ? knowledgePath : void 0,
|
|
304
|
+
refsPath: fs3.existsSync(refsPath) ? refsPath : void 0,
|
|
305
|
+
tasksPath: fs3.existsSync(tasksPath) ? tasksPath : void 0,
|
|
225
306
|
semanticSearchEnabled: config?.semanticSearchEnabled
|
|
226
307
|
});
|
|
227
308
|
}
|
|
@@ -237,29 +318,29 @@ function scanHomeDirectory(excludePath) {
|
|
|
237
318
|
function scanDir(dirPath, depth) {
|
|
238
319
|
if (depth > maxDepth) return;
|
|
239
320
|
try {
|
|
240
|
-
const entries =
|
|
321
|
+
const entries = fs3.readdirSync(dirPath, { withFileTypes: true });
|
|
241
322
|
for (const entry of entries) {
|
|
242
323
|
if (!entry.isDirectory()) continue;
|
|
243
|
-
const fullPath =
|
|
324
|
+
const fullPath = path3.join(dirPath, entry.name);
|
|
244
325
|
if (excludePath && fullPath === excludePath) continue;
|
|
245
326
|
if (entry.name === ".rrce-workflow") {
|
|
246
|
-
const configPath =
|
|
247
|
-
if (
|
|
327
|
+
const configPath = path3.join(fullPath, "config.yaml");
|
|
328
|
+
if (fs3.existsSync(configPath)) {
|
|
248
329
|
const projectPath = dirPath;
|
|
249
|
-
const projectName =
|
|
330
|
+
const projectName = path3.basename(projectPath);
|
|
250
331
|
const config = parseWorkspaceConfig(configPath);
|
|
251
|
-
const knowledgePath =
|
|
252
|
-
const refsPath =
|
|
253
|
-
const tasksPath =
|
|
332
|
+
const knowledgePath = path3.join(fullPath, "knowledge");
|
|
333
|
+
const refsPath = path3.join(fullPath, "refs");
|
|
334
|
+
const tasksPath = path3.join(fullPath, "tasks");
|
|
254
335
|
projects.push({
|
|
255
336
|
name: config?.name || projectName,
|
|
256
337
|
path: projectPath,
|
|
257
338
|
dataPath: fullPath,
|
|
258
339
|
source: "local",
|
|
259
340
|
storageMode: config?.storageMode,
|
|
260
|
-
knowledgePath:
|
|
261
|
-
refsPath:
|
|
262
|
-
tasksPath:
|
|
341
|
+
knowledgePath: fs3.existsSync(knowledgePath) ? knowledgePath : void 0,
|
|
342
|
+
refsPath: fs3.existsSync(refsPath) ? refsPath : void 0,
|
|
343
|
+
tasksPath: fs3.existsSync(tasksPath) ? tasksPath : void 0,
|
|
263
344
|
semanticSearchEnabled: config?.semanticSearchEnabled
|
|
264
345
|
});
|
|
265
346
|
}
|
|
@@ -277,7 +358,7 @@ function scanHomeDirectory(excludePath) {
|
|
|
277
358
|
}
|
|
278
359
|
function parseWorkspaceConfig(configPath) {
|
|
279
360
|
try {
|
|
280
|
-
const content =
|
|
361
|
+
const content = fs3.readFileSync(configPath, "utf-8");
|
|
281
362
|
const nameMatch = content.match(/name:\s*["']?([^"'\n]+)["']?/);
|
|
282
363
|
const sourcePathMatch = content.match(/sourcePath:\s*["']?([^"'\n]+)["']?/);
|
|
283
364
|
const modeMatch = content.match(/mode:\s*(global|workspace)/);
|
|
@@ -295,7 +376,7 @@ function parseWorkspaceConfig(configPath) {
|
|
|
295
376
|
const semanticSearchMatch = content.match(/semantic_search:\s*\n\s*enabled:\s*(true|false)/);
|
|
296
377
|
const semanticSearchEnabled = semanticSearchMatch ? semanticSearchMatch[1] === "true" : false;
|
|
297
378
|
return {
|
|
298
|
-
name: nameMatch?.[1]?.trim() ||
|
|
379
|
+
name: nameMatch?.[1]?.trim() || path3.basename(path3.dirname(path3.dirname(configPath))),
|
|
299
380
|
sourcePath: sourcePathMatch?.[1]?.trim(),
|
|
300
381
|
storageMode: modeMatch?.[1] || "global",
|
|
301
382
|
linkedProjects: linkedProjects.length > 0 ? linkedProjects : void 0,
|
|
@@ -401,8 +482,8 @@ var init_detection_service = __esm({
|
|
|
401
482
|
});
|
|
402
483
|
|
|
403
484
|
// src/lib/autocomplete-prompt.ts
|
|
404
|
-
import * as
|
|
405
|
-
import * as
|
|
485
|
+
import * as fs4 from "fs";
|
|
486
|
+
import * as path4 from "path";
|
|
406
487
|
import * as readline from "readline";
|
|
407
488
|
import pc from "picocolors";
|
|
408
489
|
function directoryPrompt(opts) {
|
|
@@ -461,19 +542,19 @@ function completeDirectory(line) {
|
|
|
461
542
|
prefix = "";
|
|
462
543
|
basePath = expanded;
|
|
463
544
|
} else {
|
|
464
|
-
dirToScan =
|
|
465
|
-
prefix =
|
|
545
|
+
dirToScan = path4.dirname(expanded);
|
|
546
|
+
prefix = path4.basename(expanded).toLowerCase();
|
|
466
547
|
basePath = dirToScan === "/" ? "/" : dirToScan + "/";
|
|
467
548
|
}
|
|
468
|
-
if (!
|
|
549
|
+
if (!fs4.existsSync(dirToScan)) {
|
|
469
550
|
return [[], line];
|
|
470
551
|
}
|
|
471
|
-
const entries =
|
|
552
|
+
const entries = fs4.readdirSync(dirToScan, { withFileTypes: true }).filter((entry) => {
|
|
472
553
|
if (!entry.isDirectory()) return false;
|
|
473
554
|
if (entry.name.startsWith(".") && !prefix.startsWith(".")) return false;
|
|
474
555
|
return prefix === "" || entry.name.toLowerCase().startsWith(prefix);
|
|
475
556
|
}).map((entry) => {
|
|
476
|
-
const fullPath =
|
|
557
|
+
const fullPath = path4.join(dirToScan, entry.name);
|
|
477
558
|
const displayPath = fullPath.startsWith(process.env.HOME || "") ? fullPath.replace(process.env.HOME || "", "~") : fullPath;
|
|
478
559
|
return displayPath + "/";
|
|
479
560
|
}).sort();
|
|
@@ -512,38 +593,6 @@ var init_autocomplete_prompt = __esm({
|
|
|
512
593
|
}
|
|
513
594
|
});
|
|
514
595
|
|
|
515
|
-
// src/lib/preferences.ts
|
|
516
|
-
import * as fs4 from "fs";
|
|
517
|
-
import * as path4 from "path";
|
|
518
|
-
function getPreferencesPath() {
|
|
519
|
-
const home = process.env.HOME || "~";
|
|
520
|
-
return path4.join(home, ".rrce-workflow", "preferences.json");
|
|
521
|
-
}
|
|
522
|
-
function loadUserPreferences() {
|
|
523
|
-
const prefPath = getPreferencesPath();
|
|
524
|
-
if (!fs4.existsSync(prefPath)) {
|
|
525
|
-
return {};
|
|
526
|
-
}
|
|
527
|
-
try {
|
|
528
|
-
return JSON.parse(fs4.readFileSync(prefPath, "utf-8"));
|
|
529
|
-
} catch {
|
|
530
|
-
return {};
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
function saveUserPreferences(prefs) {
|
|
534
|
-
const prefPath = getPreferencesPath();
|
|
535
|
-
ensureDir(path4.dirname(prefPath));
|
|
536
|
-
const current = loadUserPreferences();
|
|
537
|
-
const refined = { ...current, ...prefs };
|
|
538
|
-
fs4.writeFileSync(prefPath, JSON.stringify(refined, null, 2));
|
|
539
|
-
}
|
|
540
|
-
var init_preferences = __esm({
|
|
541
|
-
"src/lib/preferences.ts"() {
|
|
542
|
-
"use strict";
|
|
543
|
-
init_paths();
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
|
|
547
596
|
// src/lib/tui-utils.ts
|
|
548
597
|
var tui_utils_exports = {};
|
|
549
598
|
__export(tui_utils_exports, {
|
|
@@ -554,7 +603,7 @@ import pc2 from "picocolors";
|
|
|
554
603
|
import * as path5 from "path";
|
|
555
604
|
async function resolveGlobalPath() {
|
|
556
605
|
const prefs = loadUserPreferences();
|
|
557
|
-
const defaultPath = prefs.defaultGlobalPath ||
|
|
606
|
+
const defaultPath = prefs.defaultGlobalPath || getDefaultRRCEHome2();
|
|
558
607
|
const isDefaultWritable = checkWriteAccess(defaultPath);
|
|
559
608
|
const options = [
|
|
560
609
|
{
|
|
@@ -590,7 +639,7 @@ Please choose a custom path instead.`,
|
|
|
590
639
|
}
|
|
591
640
|
return defaultPath;
|
|
592
641
|
}
|
|
593
|
-
const suggestedPath = path5.join(process.env.HOME || "~", ".
|
|
642
|
+
const suggestedPath = path5.join(process.env.HOME || "~", ".rrce-workflow");
|
|
594
643
|
const customPath = await directoryPrompt({
|
|
595
644
|
message: "Enter custom global path (Tab to autocomplete):",
|
|
596
645
|
defaultValue: suggestedPath,
|
|
@@ -611,7 +660,7 @@ Please choose a custom path instead.`,
|
|
|
611
660
|
if (!expandedPath.endsWith(".rrce-workflow")) {
|
|
612
661
|
expandedPath = path5.join(expandedPath, ".rrce-workflow");
|
|
613
662
|
}
|
|
614
|
-
saveUserPreferences({ defaultGlobalPath: expandedPath });
|
|
663
|
+
saveUserPreferences({ defaultGlobalPath: expandedPath, useCustomGlobalPath: true });
|
|
615
664
|
return expandedPath;
|
|
616
665
|
}
|
|
617
666
|
var init_tui_utils = __esm({
|
|
@@ -1134,7 +1183,7 @@ function getProjectPermissions(config, name, projectPath) {
|
|
|
1134
1183
|
return project?.permissions ?? config.defaults.permissions;
|
|
1135
1184
|
}
|
|
1136
1185
|
function cleanStaleProjects(config) {
|
|
1137
|
-
const rrceHome =
|
|
1186
|
+
const rrceHome = getEffectiveGlobalPath();
|
|
1138
1187
|
const globalWorkspacesDir = path9.join(rrceHome, "workspaces");
|
|
1139
1188
|
const validProjects = [];
|
|
1140
1189
|
const removed = [];
|
|
@@ -1202,7 +1251,7 @@ function installAgentPrompts(config, workspacePath, dataPaths) {
|
|
|
1202
1251
|
function createWorkspaceConfig(config, workspacePath, workspaceName) {
|
|
1203
1252
|
let configPath;
|
|
1204
1253
|
if (config.storageMode === "global") {
|
|
1205
|
-
const rrceHome = config.globalPath ||
|
|
1254
|
+
const rrceHome = config.globalPath || getDefaultRRCEHome2();
|
|
1206
1255
|
configPath = path10.join(rrceHome, "workspaces", workspaceName, "config.yaml");
|
|
1207
1256
|
} else {
|
|
1208
1257
|
configPath = path10.join(workspacePath, ".rrce-workflow", "config.yaml");
|
|
@@ -1213,7 +1262,7 @@ version: 1
|
|
|
1213
1262
|
|
|
1214
1263
|
storage:
|
|
1215
1264
|
mode: ${config.storageMode}`;
|
|
1216
|
-
if (config.globalPath && config.globalPath !==
|
|
1265
|
+
if (config.globalPath && config.globalPath !== getDefaultRRCEHome2()) {
|
|
1217
1266
|
content += `
|
|
1218
1267
|
globalPath: "${config.globalPath}"`;
|
|
1219
1268
|
}
|
|
@@ -1249,25 +1298,14 @@ async function registerWithMCP(config, workspacePath, workspaceName) {
|
|
|
1249
1298
|
try {
|
|
1250
1299
|
const { loadMCPConfig: loadMCPConfig3, saveMCPConfig: saveMCPConfig2, setProjectConfig: setProjectConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1251
1300
|
const mcpConfig = loadMCPConfig3();
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
);
|
|
1261
|
-
} else {
|
|
1262
|
-
setProjectConfig2(
|
|
1263
|
-
mcpConfig,
|
|
1264
|
-
workspaceName,
|
|
1265
|
-
true,
|
|
1266
|
-
void 0,
|
|
1267
|
-
workspacePath,
|
|
1268
|
-
config.enableRAG ? { enabled: true } : void 0
|
|
1269
|
-
);
|
|
1270
|
-
}
|
|
1301
|
+
setProjectConfig2(
|
|
1302
|
+
mcpConfig,
|
|
1303
|
+
workspaceName,
|
|
1304
|
+
true,
|
|
1305
|
+
void 0,
|
|
1306
|
+
workspacePath,
|
|
1307
|
+
config.enableRAG ? { enabled: true } : void 0
|
|
1308
|
+
);
|
|
1271
1309
|
saveMCPConfig2(mcpConfig);
|
|
1272
1310
|
} catch (e) {
|
|
1273
1311
|
note2(
|
|
@@ -1280,7 +1318,7 @@ You can configure MCP later: ${pc4.cyan("npx rrce-workflow mcp")}`,
|
|
|
1280
1318
|
}
|
|
1281
1319
|
}
|
|
1282
1320
|
function getDataPaths(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
1283
|
-
const globalPath = path10.join(customGlobalPath ||
|
|
1321
|
+
const globalPath = path10.join(customGlobalPath || getDefaultRRCEHome2(), "workspaces", workspaceName);
|
|
1284
1322
|
const workspacePath = path10.join(workspaceRoot, ".rrce-workflow");
|
|
1285
1323
|
switch (mode) {
|
|
1286
1324
|
case "global":
|
|
@@ -1664,7 +1702,8 @@ import * as fs13 from "fs";
|
|
|
1664
1702
|
import * as path14 from "path";
|
|
1665
1703
|
function getExposedProjects() {
|
|
1666
1704
|
const config = loadMCPConfig();
|
|
1667
|
-
const
|
|
1705
|
+
const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
|
|
1706
|
+
const allProjects = projectService.scan({ knownPaths });
|
|
1668
1707
|
const globalProjects = allProjects.filter((project) => isProjectExposed(config, project.name, project.dataPath));
|
|
1669
1708
|
const activeProject = detectActiveProject(globalProjects);
|
|
1670
1709
|
let linkedProjects = [];
|
|
@@ -1716,7 +1755,8 @@ function detectActiveProject(knownProjects) {
|
|
|
1716
1755
|
let scanList = knownProjects;
|
|
1717
1756
|
if (!scanList) {
|
|
1718
1757
|
const config = loadMCPConfig();
|
|
1719
|
-
const
|
|
1758
|
+
const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
|
|
1759
|
+
const all = projectService.scan({ knownPaths });
|
|
1720
1760
|
scanList = all.filter((project) => isProjectExposed(config, project.name, project.dataPath));
|
|
1721
1761
|
}
|
|
1722
1762
|
return findClosestProject(scanList);
|
|
@@ -2285,6 +2325,7 @@ import {
|
|
|
2285
2325
|
ListPromptsRequestSchema,
|
|
2286
2326
|
GetPromptRequestSchema
|
|
2287
2327
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
2328
|
+
import * as path15 from "path";
|
|
2288
2329
|
function registerPromptHandlers(server) {
|
|
2289
2330
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
2290
2331
|
logger.debug("Listing prompts");
|
|
@@ -2319,8 +2360,35 @@ function registerPromptHandlers(server) {
|
|
|
2319
2360
|
for (const [key, val] of Object.entries(providedArgs)) {
|
|
2320
2361
|
renderArgs[key] = String(val);
|
|
2321
2362
|
}
|
|
2363
|
+
const activeProject = detectActiveProject();
|
|
2364
|
+
const DEFAULT_RRCE_HOME = getEffectiveGlobalPath();
|
|
2365
|
+
let resolvedRrceData = ".rrce-workflow/";
|
|
2366
|
+
let resolvedRrceHome = DEFAULT_RRCE_HOME;
|
|
2367
|
+
let resolvedWorkspaceRoot = process.cwd();
|
|
2368
|
+
let resolvedWorkspaceName = "current-project";
|
|
2369
|
+
if (activeProject) {
|
|
2370
|
+
resolvedRrceData = activeProject.dataPath + "/";
|
|
2371
|
+
resolvedWorkspaceRoot = activeProject.sourcePath || activeProject.path || activeProject.dataPath;
|
|
2372
|
+
resolvedWorkspaceName = activeProject.name;
|
|
2373
|
+
if (activeProject.source === "global") {
|
|
2374
|
+
const workspacesDir = path15.dirname(activeProject.dataPath);
|
|
2375
|
+
resolvedRrceHome = path15.dirname(workspacesDir);
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
if (!renderArgs["RRCE_DATA"]) renderArgs["RRCE_DATA"] = resolvedRrceData;
|
|
2379
|
+
if (!renderArgs["RRCE_HOME"]) renderArgs["RRCE_HOME"] = resolvedRrceHome;
|
|
2380
|
+
if (!renderArgs["WORKSPACE_ROOT"]) renderArgs["WORKSPACE_ROOT"] = resolvedWorkspaceRoot;
|
|
2381
|
+
if (!renderArgs["WORKSPACE_NAME"]) renderArgs["WORKSPACE_NAME"] = resolvedWorkspaceName;
|
|
2322
2382
|
const content = renderPrompt(promptDef.content, renderArgs);
|
|
2323
|
-
|
|
2383
|
+
let contextPreamble = getContextPreamble();
|
|
2384
|
+
contextPreamble += `
|
|
2385
|
+
### System Resolved Paths (OVERRIDE)
|
|
2386
|
+
The system has pre-resolved the configuration for this project. Use these values instead of manual resolution:
|
|
2387
|
+
- **RRCE_DATA**: \`${resolvedRrceData}\` (Stores knowledge, tasks, refs)
|
|
2388
|
+
- **WORKSPACE_ROOT**: \`${resolvedWorkspaceRoot}\` (Source code location)
|
|
2389
|
+
- **RRCE_HOME**: \`${resolvedRrceHome}\`
|
|
2390
|
+
- **Current Project**: ${resolvedWorkspaceName}
|
|
2391
|
+
`;
|
|
2324
2392
|
return {
|
|
2325
2393
|
messages: [
|
|
2326
2394
|
{
|
|
@@ -2344,6 +2412,7 @@ var init_prompts3 = __esm({
|
|
|
2344
2412
|
init_logger();
|
|
2345
2413
|
init_resources();
|
|
2346
2414
|
init_prompts2();
|
|
2415
|
+
init_paths();
|
|
2347
2416
|
}
|
|
2348
2417
|
});
|
|
2349
2418
|
|
|
@@ -2426,7 +2495,7 @@ var init_server = __esm({
|
|
|
2426
2495
|
|
|
2427
2496
|
// src/mcp/install.ts
|
|
2428
2497
|
import * as fs14 from "fs";
|
|
2429
|
-
import * as
|
|
2498
|
+
import * as path16 from "path";
|
|
2430
2499
|
import * as os from "os";
|
|
2431
2500
|
function checkInstallStatus(workspacePath) {
|
|
2432
2501
|
return {
|
|
@@ -2464,7 +2533,7 @@ function checkVSCodeGlobalConfig() {
|
|
|
2464
2533
|
}
|
|
2465
2534
|
}
|
|
2466
2535
|
function checkVSCodeWorkspaceConfig(workspacePath) {
|
|
2467
|
-
const configPath =
|
|
2536
|
+
const configPath = path16.join(workspacePath, ".vscode", "mcp.json");
|
|
2468
2537
|
if (!fs14.existsSync(configPath)) return false;
|
|
2469
2538
|
try {
|
|
2470
2539
|
const content = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
|
|
@@ -2492,7 +2561,7 @@ function installToConfig(target, workspacePath) {
|
|
|
2492
2561
|
}
|
|
2493
2562
|
}
|
|
2494
2563
|
function installToAntigravity() {
|
|
2495
|
-
const dir =
|
|
2564
|
+
const dir = path16.dirname(ANTIGRAVITY_CONFIG);
|
|
2496
2565
|
if (!fs14.existsSync(dir)) {
|
|
2497
2566
|
fs14.mkdirSync(dir, { recursive: true });
|
|
2498
2567
|
}
|
|
@@ -2516,7 +2585,7 @@ function installToAntigravity() {
|
|
|
2516
2585
|
}
|
|
2517
2586
|
}
|
|
2518
2587
|
function installToClaude() {
|
|
2519
|
-
const dir =
|
|
2588
|
+
const dir = path16.dirname(CLAUDE_CONFIG);
|
|
2520
2589
|
if (!fs14.existsSync(dir)) {
|
|
2521
2590
|
fs14.mkdirSync(dir, { recursive: true });
|
|
2522
2591
|
}
|
|
@@ -2540,7 +2609,7 @@ function installToClaude() {
|
|
|
2540
2609
|
}
|
|
2541
2610
|
}
|
|
2542
2611
|
function installToVSCodeGlobal() {
|
|
2543
|
-
const dir =
|
|
2612
|
+
const dir = path16.dirname(VSCODE_GLOBAL_CONFIG);
|
|
2544
2613
|
if (!fs14.existsSync(dir)) {
|
|
2545
2614
|
fs14.mkdirSync(dir, { recursive: true });
|
|
2546
2615
|
}
|
|
@@ -2564,8 +2633,8 @@ function installToVSCodeGlobal() {
|
|
|
2564
2633
|
}
|
|
2565
2634
|
}
|
|
2566
2635
|
function installToVSCodeWorkspace(workspacePath) {
|
|
2567
|
-
const vscodeDir =
|
|
2568
|
-
const configPath =
|
|
2636
|
+
const vscodeDir = path16.join(workspacePath, ".vscode");
|
|
2637
|
+
const configPath = path16.join(vscodeDir, "mcp.json");
|
|
2569
2638
|
if (!fs14.existsSync(vscodeDir)) {
|
|
2570
2639
|
fs14.mkdirSync(vscodeDir, { recursive: true });
|
|
2571
2640
|
}
|
|
@@ -2606,9 +2675,9 @@ var ANTIGRAVITY_CONFIG, CLAUDE_CONFIG, VSCODE_GLOBAL_CONFIG;
|
|
|
2606
2675
|
var init_install = __esm({
|
|
2607
2676
|
"src/mcp/install.ts"() {
|
|
2608
2677
|
"use strict";
|
|
2609
|
-
ANTIGRAVITY_CONFIG =
|
|
2610
|
-
CLAUDE_CONFIG =
|
|
2611
|
-
VSCODE_GLOBAL_CONFIG =
|
|
2678
|
+
ANTIGRAVITY_CONFIG = path16.join(os.homedir(), ".gemini/antigravity/mcp_config.json");
|
|
2679
|
+
CLAUDE_CONFIG = path16.join(os.homedir(), ".config/claude/claude_desktop_config.json");
|
|
2680
|
+
VSCODE_GLOBAL_CONFIG = path16.join(os.homedir(), ".config/Code/User/settings.json");
|
|
2612
2681
|
}
|
|
2613
2682
|
});
|
|
2614
2683
|
|
|
@@ -2619,7 +2688,8 @@ async function handleConfigure() {
|
|
|
2619
2688
|
const s = spinner();
|
|
2620
2689
|
s.start("Scanning for projects...");
|
|
2621
2690
|
const config = loadMCPConfig();
|
|
2622
|
-
const
|
|
2691
|
+
const knownPaths = config.projects.map((p) => p.path).filter((p) => !!p);
|
|
2692
|
+
const projects = scanForProjects({ knownPaths });
|
|
2623
2693
|
logger.info("Configure: Loaded config", { projects: config.projects, defaultMode: config.defaults.includeNew });
|
|
2624
2694
|
s.stop("Projects found");
|
|
2625
2695
|
if (projects.length === 0) {
|
|
@@ -2694,7 +2764,7 @@ Hidden projects: ${projects.length - exposedCount}`,
|
|
|
2694
2764
|
async function handleConfigureGlobalPath() {
|
|
2695
2765
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
2696
2766
|
const fs21 = await import("fs");
|
|
2697
|
-
const
|
|
2767
|
+
const path20 = await import("path");
|
|
2698
2768
|
note3(
|
|
2699
2769
|
`MCP Hub requires a ${pc5.bold("global storage path")} to store its configuration
|
|
2700
2770
|
and coordinate across projects.
|
|
@@ -2717,7 +2787,7 @@ locally in each project. MCP needs a central location.`,
|
|
|
2717
2787
|
`${pc5.green("\u2713")} Global path configured: ${pc5.cyan(resolvedPath)}
|
|
2718
2788
|
|
|
2719
2789
|
MCP config will be stored at:
|
|
2720
|
-
${
|
|
2790
|
+
${path20.join(resolvedPath, "mcp.yaml")}`,
|
|
2721
2791
|
"Configuration Saved"
|
|
2722
2792
|
);
|
|
2723
2793
|
return true;
|
|
@@ -4073,14 +4143,14 @@ var init_link_flow = __esm({
|
|
|
4073
4143
|
import { confirm as confirm7, spinner as spinner5, note as note10, outro as outro4, cancel as cancel5, isCancel as isCancel9 } from "@clack/prompts";
|
|
4074
4144
|
import pc12 from "picocolors";
|
|
4075
4145
|
import * as fs17 from "fs";
|
|
4076
|
-
import * as
|
|
4146
|
+
import * as path17 from "path";
|
|
4077
4147
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
4078
4148
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
4079
4149
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
4080
|
-
const globalPath =
|
|
4150
|
+
const globalPath = path17.join(customGlobalPath, "workspaces", workspaceName);
|
|
4081
4151
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
4082
4152
|
const existingDirs = subdirs.filter(
|
|
4083
|
-
(dir) => fs17.existsSync(
|
|
4153
|
+
(dir) => fs17.existsSync(path17.join(localPath, dir))
|
|
4084
4154
|
);
|
|
4085
4155
|
if (existingDirs.length === 0) {
|
|
4086
4156
|
outro4(pc12.yellow("No data found in workspace storage to sync."));
|
|
@@ -4106,8 +4176,8 @@ Destination: ${pc12.cyan(globalPath)}`,
|
|
|
4106
4176
|
try {
|
|
4107
4177
|
ensureDir(globalPath);
|
|
4108
4178
|
for (const dir of existingDirs) {
|
|
4109
|
-
const srcDir =
|
|
4110
|
-
const destDir =
|
|
4179
|
+
const srcDir = path17.join(localPath, dir);
|
|
4180
|
+
const destDir = path17.join(globalPath, dir);
|
|
4111
4181
|
ensureDir(destDir);
|
|
4112
4182
|
copyDirRecursive(srcDir, destDir);
|
|
4113
4183
|
}
|
|
@@ -4140,7 +4210,7 @@ var init_sync_flow = __esm({
|
|
|
4140
4210
|
import { confirm as confirm8, spinner as spinner6, note as note11, outro as outro5, cancel as cancel6, isCancel as isCancel10 } from "@clack/prompts";
|
|
4141
4211
|
import pc13 from "picocolors";
|
|
4142
4212
|
import * as fs18 from "fs";
|
|
4143
|
-
import * as
|
|
4213
|
+
import * as path18 from "path";
|
|
4144
4214
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
4145
4215
|
const s = spinner6();
|
|
4146
4216
|
s.start("Checking for updates");
|
|
@@ -4170,7 +4240,7 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
4170
4240
|
}
|
|
4171
4241
|
s.start("Updating from package");
|
|
4172
4242
|
for (const dataPath of dataPaths) {
|
|
4173
|
-
copyDirToAllStoragePaths(
|
|
4243
|
+
copyDirToAllStoragePaths(path18.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
4174
4244
|
}
|
|
4175
4245
|
const configFilePath = getConfigPath(workspacePath);
|
|
4176
4246
|
if (fs18.existsSync(configFilePath)) {
|
|
@@ -4203,8 +4273,8 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
4203
4273
|
}
|
|
4204
4274
|
}
|
|
4205
4275
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
4206
|
-
const globalPath =
|
|
4207
|
-
const workspacePath =
|
|
4276
|
+
const globalPath = path18.join(customGlobalPath, "workspaces", workspaceName);
|
|
4277
|
+
const workspacePath = path18.join(workspaceRoot, ".rrce-workflow");
|
|
4208
4278
|
switch (mode) {
|
|
4209
4279
|
case "global":
|
|
4210
4280
|
return [globalPath];
|
|
@@ -4436,9 +4506,9 @@ init_wizard();
|
|
|
4436
4506
|
init_prompts();
|
|
4437
4507
|
import { intro as intro3, select as select6, note as note14, cancel as cancel9, isCancel as isCancel13, outro as outro8 } from "@clack/prompts";
|
|
4438
4508
|
import pc16 from "picocolors";
|
|
4439
|
-
import * as
|
|
4509
|
+
import * as path19 from "path";
|
|
4440
4510
|
async function runSelector() {
|
|
4441
|
-
const workspaceName =
|
|
4511
|
+
const workspaceName = path19.basename(process.cwd());
|
|
4442
4512
|
intro3(pc16.cyan(pc16.inverse(` RRCE-Workflow | ${workspaceName} `)));
|
|
4443
4513
|
const prompts = loadPromptsFromDir(getAgentCorePromptsDir());
|
|
4444
4514
|
if (prompts.length === 0) {
|