rrce-workflow 0.2.92 → 0.2.94
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/dist/index.js +629 -144
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1562,6 +1562,33 @@ var init_rag = __esm({
|
|
|
1562
1562
|
logger.error(`[RAG] Failed to save index to ${this.indexPath}`, error);
|
|
1563
1563
|
}
|
|
1564
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
|
+
}
|
|
1565
1592
|
/**
|
|
1566
1593
|
* Generate embedding for text
|
|
1567
1594
|
*/
|
|
@@ -1612,7 +1639,7 @@ var init_rag = __esm({
|
|
|
1612
1639
|
mtime: mtime ?? Date.now(),
|
|
1613
1640
|
chunkCount: chunks.length
|
|
1614
1641
|
};
|
|
1615
|
-
this.
|
|
1642
|
+
this.maybeSaveIndex();
|
|
1616
1643
|
return true;
|
|
1617
1644
|
}
|
|
1618
1645
|
/**
|
|
@@ -1628,7 +1655,7 @@ var init_rag = __esm({
|
|
|
1628
1655
|
}
|
|
1629
1656
|
if (this.index.chunks.length !== initialCount) {
|
|
1630
1657
|
logger.info(`[RAG] Removed file ${filePath} from index (${initialCount - this.index.chunks.length} chunks removed)`);
|
|
1631
|
-
this.
|
|
1658
|
+
this.maybeSaveIndex(true);
|
|
1632
1659
|
}
|
|
1633
1660
|
}
|
|
1634
1661
|
/**
|
|
@@ -1651,7 +1678,7 @@ var init_rag = __esm({
|
|
|
1651
1678
|
this.loadIndex();
|
|
1652
1679
|
if (!this.index) return;
|
|
1653
1680
|
this.index.lastFullIndex = Date.now();
|
|
1654
|
-
this.
|
|
1681
|
+
this.maybeSaveIndex(true);
|
|
1655
1682
|
}
|
|
1656
1683
|
/**
|
|
1657
1684
|
* Search the index
|
|
@@ -1681,9 +1708,11 @@ var init_rag = __esm({
|
|
|
1681
1708
|
let normA = 0;
|
|
1682
1709
|
let normB = 0;
|
|
1683
1710
|
for (let i = 0; i < a.length; i++) {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1711
|
+
const av = a[i] ?? 0;
|
|
1712
|
+
const bv = b[i] ?? 0;
|
|
1713
|
+
dotProduct += av * bv;
|
|
1714
|
+
normA += av * av;
|
|
1715
|
+
normB += bv * bv;
|
|
1687
1716
|
}
|
|
1688
1717
|
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
1689
1718
|
}
|
|
@@ -1716,6 +1745,83 @@ var init_rag = __esm({
|
|
|
1716
1745
|
}
|
|
1717
1746
|
});
|
|
1718
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
|
+
|
|
1719
1825
|
// src/mcp/resources.ts
|
|
1720
1826
|
import * as fs14 from "fs";
|
|
1721
1827
|
import * as path16 from "path";
|
|
@@ -1887,6 +1993,8 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1887
1993
|
if (projectFilter && project.name !== projectFilter) continue;
|
|
1888
1994
|
const permissions = getProjectPermissions(config, project.name, project.sourcePath || project.path);
|
|
1889
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;
|
|
1890
1998
|
const projConfig = config.projects.find(
|
|
1891
1999
|
(p) => p.path && normalizeProjectPath(p.path) === normalizeProjectPath(project.sourcePath || project.path) || !p.path && p.name === project.name
|
|
1892
2000
|
);
|
|
@@ -1903,7 +2011,9 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1903
2011
|
file: path16.relative(project.knowledgePath, r.filePath),
|
|
1904
2012
|
matches: [r.content],
|
|
1905
2013
|
// The chunk content is the match
|
|
1906
|
-
score: r.score
|
|
2014
|
+
score: r.score,
|
|
2015
|
+
indexingInProgress: indexingInProgress || void 0,
|
|
2016
|
+
advisoryMessage
|
|
1907
2017
|
});
|
|
1908
2018
|
}
|
|
1909
2019
|
continue;
|
|
@@ -1928,8 +2038,10 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1928
2038
|
results.push({
|
|
1929
2039
|
project: project.name,
|
|
1930
2040
|
file,
|
|
1931
|
-
matches: matches.slice(0, 5)
|
|
2041
|
+
matches: matches.slice(0, 5),
|
|
1932
2042
|
// Limit to 5 matches per file
|
|
2043
|
+
indexingInProgress: indexingInProgress || void 0,
|
|
2044
|
+
advisoryMessage
|
|
1933
2045
|
});
|
|
1934
2046
|
}
|
|
1935
2047
|
}
|
|
@@ -1941,20 +2053,44 @@ async function searchKnowledge(query, projectFilter) {
|
|
|
1941
2053
|
async function indexKnowledge(projectName, force = false) {
|
|
1942
2054
|
const config = loadMCPConfig();
|
|
1943
2055
|
const projects = getExposedProjects();
|
|
1944
|
-
const project = projects.find((
|
|
2056
|
+
const project = projects.find((p2) => p2.name === projectName || p2.path && p2.path === projectName);
|
|
1945
2057
|
if (!project) {
|
|
1946
|
-
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
|
+
};
|
|
1947
2067
|
}
|
|
1948
2068
|
const projConfig = config.projects.find(
|
|
1949
|
-
(
|
|
2069
|
+
(p2) => p2.path && normalizeProjectPath(p2.path) === normalizeProjectPath(project.sourcePath || project.path) || !p2.path && p2.name === project.name
|
|
1950
2070
|
) || (project.source === "global" ? { semanticSearch: { enabled: true, model: "Xenova/all-MiniLM-L6-v2" } } : void 0);
|
|
1951
2071
|
const isEnabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled;
|
|
1952
2072
|
if (!isEnabled) {
|
|
1953
|
-
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
|
+
};
|
|
1954
2082
|
}
|
|
1955
2083
|
const scanRoot = project.sourcePath || project.path || project.dataPath;
|
|
1956
2084
|
if (!fs14.existsSync(scanRoot)) {
|
|
1957
|
-
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
|
+
};
|
|
1958
2094
|
}
|
|
1959
2095
|
const INDEXABLE_EXTENSIONS = [
|
|
1960
2096
|
".ts",
|
|
@@ -1995,18 +2131,37 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
1995
2131
|
".less"
|
|
1996
2132
|
];
|
|
1997
2133
|
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "venv", ".venv", "target", "vendor"];
|
|
1998
|
-
|
|
2134
|
+
const runIndexing = async () => {
|
|
1999
2135
|
const indexPath = path16.join(project.knowledgePath || path16.join(scanRoot, ".rrce-workflow", "knowledge"), "embeddings.json");
|
|
2000
2136
|
const model = projConfig?.semanticSearch?.model || "Xenova/all-MiniLM-L6-v2";
|
|
2001
2137
|
const rag = new RAGService(indexPath, model);
|
|
2002
2138
|
let indexed = 0;
|
|
2003
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 });
|
|
2004
2159
|
const scanDir = async (dir) => {
|
|
2005
2160
|
const entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
2006
2161
|
for (const entry of entries) {
|
|
2007
2162
|
const fullPath = path16.join(dir, entry.name);
|
|
2008
2163
|
if (entry.isDirectory()) {
|
|
2009
|
-
if (
|
|
2164
|
+
if (shouldSkipDir(entry.name)) {
|
|
2010
2165
|
continue;
|
|
2011
2166
|
}
|
|
2012
2167
|
await scanDir(fullPath);
|
|
@@ -2016,6 +2171,7 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2016
2171
|
continue;
|
|
2017
2172
|
}
|
|
2018
2173
|
try {
|
|
2174
|
+
indexingJobs.update(project.name, { currentItem: fullPath, itemsDone });
|
|
2019
2175
|
const stat = fs14.statSync(fullPath);
|
|
2020
2176
|
const mtime = force ? void 0 : stat.mtimeMs;
|
|
2021
2177
|
const content = fs14.readFileSync(fullPath, "utf-8");
|
|
@@ -2026,6 +2182,12 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2026
2182
|
skipped++;
|
|
2027
2183
|
}
|
|
2028
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
|
+
}
|
|
2029
2191
|
}
|
|
2030
2192
|
}
|
|
2031
2193
|
}
|
|
@@ -2033,15 +2195,28 @@ async function indexKnowledge(projectName, force = false) {
|
|
|
2033
2195
|
await scanDir(scanRoot);
|
|
2034
2196
|
rag.markFullIndex();
|
|
2035
2197
|
const stats = rag.getStats();
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
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
|
+
};
|
|
2045
2220
|
}
|
|
2046
2221
|
function getContextPreamble() {
|
|
2047
2222
|
const projects = getExposedProjects();
|
|
@@ -2189,6 +2364,7 @@ var init_resources = __esm({
|
|
|
2189
2364
|
init_detection();
|
|
2190
2365
|
init_detection_service();
|
|
2191
2366
|
init_rag();
|
|
2367
|
+
init_indexing_jobs();
|
|
2192
2368
|
init_paths();
|
|
2193
2369
|
}
|
|
2194
2370
|
});
|
|
@@ -2905,8 +3081,8 @@ Hidden projects: ${projects.length - exposedCount}`,
|
|
|
2905
3081
|
}
|
|
2906
3082
|
async function handleConfigureGlobalPath() {
|
|
2907
3083
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
2908
|
-
const
|
|
2909
|
-
const
|
|
3084
|
+
const fs23 = await import("fs");
|
|
3085
|
+
const path21 = await import("path");
|
|
2910
3086
|
note3(
|
|
2911
3087
|
`MCP Hub requires a ${pc5.bold("global storage path")} to store its configuration
|
|
2912
3088
|
and coordinate across projects.
|
|
@@ -2920,8 +3096,8 @@ locally in each project. MCP needs a central location.`,
|
|
|
2920
3096
|
return false;
|
|
2921
3097
|
}
|
|
2922
3098
|
try {
|
|
2923
|
-
if (!
|
|
2924
|
-
|
|
3099
|
+
if (!fs23.existsSync(resolvedPath)) {
|
|
3100
|
+
fs23.mkdirSync(resolvedPath, { recursive: true });
|
|
2925
3101
|
}
|
|
2926
3102
|
const config = loadMCPConfig();
|
|
2927
3103
|
saveMCPConfig(config);
|
|
@@ -2929,7 +3105,7 @@ locally in each project. MCP needs a central location.`,
|
|
|
2929
3105
|
`${pc5.green("\u2713")} Global path configured: ${pc5.cyan(resolvedPath)}
|
|
2930
3106
|
|
|
2931
3107
|
MCP config will be stored at:
|
|
2932
|
-
${
|
|
3108
|
+
${path21.join(resolvedPath, "mcp.yaml")}`,
|
|
2933
3109
|
"Configuration Saved"
|
|
2934
3110
|
);
|
|
2935
3111
|
return true;
|
|
@@ -3169,46 +3345,234 @@ var init_SimpleSelect = __esm({
|
|
|
3169
3345
|
}
|
|
3170
3346
|
});
|
|
3171
3347
|
|
|
3348
|
+
// src/mcp/ui/lib/tasks-fs.ts
|
|
3349
|
+
import * as fs16 from "fs";
|
|
3350
|
+
import * as path18 from "path";
|
|
3351
|
+
function detectStorageModeFromConfig(workspaceRoot) {
|
|
3352
|
+
const configPath = getConfigPath(workspaceRoot);
|
|
3353
|
+
try {
|
|
3354
|
+
const rrceHome = getEffectiveGlobalBase();
|
|
3355
|
+
if (configPath.startsWith(rrceHome)) {
|
|
3356
|
+
return "global";
|
|
3357
|
+
}
|
|
3358
|
+
if (fs16.existsSync(configPath)) {
|
|
3359
|
+
const content = fs16.readFileSync(configPath, "utf-8");
|
|
3360
|
+
if (content.includes("mode: workspace")) return "workspace";
|
|
3361
|
+
if (content.includes("mode: global")) return "global";
|
|
3362
|
+
}
|
|
3363
|
+
} catch {
|
|
3364
|
+
}
|
|
3365
|
+
return "global";
|
|
3366
|
+
}
|
|
3367
|
+
function getEffectiveGlobalBase() {
|
|
3368
|
+
const dummy = resolveDataPath("global", "__rrce_dummy__", "");
|
|
3369
|
+
return path18.dirname(path18.dirname(dummy));
|
|
3370
|
+
}
|
|
3371
|
+
function getProjectRRCEData(project) {
|
|
3372
|
+
const workspaceRoot = project.sourcePath || project.path;
|
|
3373
|
+
const mode = detectStorageModeFromConfig(workspaceRoot);
|
|
3374
|
+
return resolveDataPath(mode, project.name, workspaceRoot);
|
|
3375
|
+
}
|
|
3376
|
+
function listProjectTasks(project) {
|
|
3377
|
+
const rrceData = getProjectRRCEData(project);
|
|
3378
|
+
const tasksPath = path18.join(rrceData, "tasks");
|
|
3379
|
+
if (!fs16.existsSync(tasksPath)) {
|
|
3380
|
+
return { projectName: project.name, tasksPath, tasks: [] };
|
|
3381
|
+
}
|
|
3382
|
+
const tasks = [];
|
|
3383
|
+
try {
|
|
3384
|
+
const entries = fs16.readdirSync(tasksPath, { withFileTypes: true });
|
|
3385
|
+
for (const entry of entries) {
|
|
3386
|
+
if (!entry.isDirectory()) continue;
|
|
3387
|
+
const metaPath = path18.join(tasksPath, entry.name, "meta.json");
|
|
3388
|
+
if (!fs16.existsSync(metaPath)) continue;
|
|
3389
|
+
try {
|
|
3390
|
+
const raw = fs16.readFileSync(metaPath, "utf-8");
|
|
3391
|
+
const meta = JSON.parse(raw);
|
|
3392
|
+
if (!meta.task_slug) meta.task_slug = entry.name;
|
|
3393
|
+
tasks.push(meta);
|
|
3394
|
+
} catch {
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
} catch {
|
|
3398
|
+
}
|
|
3399
|
+
tasks.sort((a, b) => {
|
|
3400
|
+
const aTime = Date.parse(a.updated_at || a.created_at || "") || 0;
|
|
3401
|
+
const bTime = Date.parse(b.updated_at || b.created_at || "") || 0;
|
|
3402
|
+
if (aTime !== bTime) return bTime - aTime;
|
|
3403
|
+
return String(a.task_slug).localeCompare(String(b.task_slug));
|
|
3404
|
+
});
|
|
3405
|
+
return { projectName: project.name, tasksPath, tasks };
|
|
3406
|
+
}
|
|
3407
|
+
function updateTaskStatus(project, taskSlug, status) {
|
|
3408
|
+
const rrceData = getProjectRRCEData(project);
|
|
3409
|
+
const metaPath = path18.join(rrceData, "tasks", taskSlug, "meta.json");
|
|
3410
|
+
if (!fs16.existsSync(metaPath)) {
|
|
3411
|
+
return { ok: false, error: `meta.json not found for task '${taskSlug}'` };
|
|
3412
|
+
}
|
|
3413
|
+
try {
|
|
3414
|
+
const meta = JSON.parse(fs16.readFileSync(metaPath, "utf-8"));
|
|
3415
|
+
const next = {
|
|
3416
|
+
...meta,
|
|
3417
|
+
status,
|
|
3418
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3419
|
+
};
|
|
3420
|
+
fs16.writeFileSync(metaPath, JSON.stringify(next, null, 2));
|
|
3421
|
+
return { ok: true, meta: next };
|
|
3422
|
+
} catch (e) {
|
|
3423
|
+
return { ok: false, error: String(e) };
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
var init_tasks_fs = __esm({
|
|
3427
|
+
"src/mcp/ui/lib/tasks-fs.ts"() {
|
|
3428
|
+
"use strict";
|
|
3429
|
+
init_paths();
|
|
3430
|
+
}
|
|
3431
|
+
});
|
|
3432
|
+
|
|
3172
3433
|
// src/mcp/ui/ProjectsView.tsx
|
|
3173
|
-
import { useState as useState2 } from "react";
|
|
3434
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
|
|
3174
3435
|
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
3175
3436
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
3176
|
-
|
|
3437
|
+
function nextStatus(current) {
|
|
3438
|
+
const idx = STATUS_CYCLE.indexOf(current || "");
|
|
3439
|
+
if (idx === -1) return STATUS_CYCLE[0];
|
|
3440
|
+
return STATUS_CYCLE[(idx + 1) % STATUS_CYCLE.length];
|
|
3441
|
+
}
|
|
3442
|
+
function projectKey(p) {
|
|
3443
|
+
return p.sourcePath ?? p.path;
|
|
3444
|
+
}
|
|
3445
|
+
function formatProjectLabel(p) {
|
|
3446
|
+
const root = p.sourcePath ?? p.path;
|
|
3447
|
+
return `${p.name} (${p.source})${root ? ` - ${root}` : ""}`;
|
|
3448
|
+
}
|
|
3449
|
+
var STATUS_CYCLE, ProjectsView;
|
|
3177
3450
|
var init_ProjectsView = __esm({
|
|
3178
3451
|
"src/mcp/ui/ProjectsView.tsx"() {
|
|
3179
3452
|
"use strict";
|
|
3180
3453
|
init_SimpleSelect();
|
|
3181
3454
|
init_config();
|
|
3455
|
+
init_tasks_fs();
|
|
3456
|
+
STATUS_CYCLE = ["pending", "in_progress", "blocked", "complete"];
|
|
3182
3457
|
ProjectsView = ({ config: initialConfig, projects: allProjects, onConfigChange }) => {
|
|
3183
3458
|
const [config, setConfig] = useState2(initialConfig);
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3459
|
+
const [mode, setMode] = useState2("expose");
|
|
3460
|
+
const [expanded, setExpanded] = useState2(() => /* @__PURE__ */ new Set());
|
|
3461
|
+
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
3462
|
+
const [taskCache, setTaskCache] = useState2({});
|
|
3463
|
+
const [errorLine, setErrorLine] = useState2(null);
|
|
3464
|
+
const sortedProjects = useMemo2(() => {
|
|
3465
|
+
return [...allProjects].sort((a, b) => {
|
|
3466
|
+
const byName = a.name.localeCompare(b.name);
|
|
3467
|
+
if (byName !== 0) return byName;
|
|
3468
|
+
return projectKey(a).localeCompare(projectKey(b));
|
|
3469
|
+
});
|
|
3470
|
+
}, [allProjects]);
|
|
3471
|
+
const refreshTasksForProject = (project) => {
|
|
3472
|
+
const res = listProjectTasks(project);
|
|
3473
|
+
setTaskCache((prev) => ({ ...prev, [projectKey(project)]: res.tasks }));
|
|
3474
|
+
};
|
|
3475
|
+
const refreshAllTasks = () => {
|
|
3476
|
+
const next = {};
|
|
3477
|
+
for (const p of sortedProjects) {
|
|
3478
|
+
next[projectKey(p)] = listProjectTasks(p).tasks;
|
|
3479
|
+
}
|
|
3480
|
+
setTaskCache(next);
|
|
3481
|
+
};
|
|
3482
|
+
useInput2((input, key) => {
|
|
3483
|
+
if (input === "t") {
|
|
3484
|
+
setErrorLine(null);
|
|
3485
|
+
setMode((prev) => prev === "expose" ? "tasks" : "expose");
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
if (mode === "expose") {
|
|
3489
|
+
if (input === "a") {
|
|
3490
|
+
const newConfig = {
|
|
3491
|
+
...config,
|
|
3492
|
+
defaults: {
|
|
3493
|
+
...config.defaults,
|
|
3494
|
+
includeNew: !config.defaults.includeNew
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3497
|
+
saveMCPConfig(newConfig);
|
|
3498
|
+
setConfig(newConfig);
|
|
3499
|
+
onConfigChange?.();
|
|
3500
|
+
}
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
if (mode === "tasks") {
|
|
3504
|
+
if (input === "R") {
|
|
3505
|
+
setErrorLine(null);
|
|
3506
|
+
refreshAllTasks();
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3509
|
+
if (key.upArrow) {
|
|
3510
|
+
setSelectedIndex((prev) => prev > 0 ? prev - 1 : Math.max(0, flattenedRows.length - 1));
|
|
3511
|
+
return;
|
|
3512
|
+
}
|
|
3513
|
+
if (key.downArrow) {
|
|
3514
|
+
setSelectedIndex((prev) => prev < flattenedRows.length - 1 ? prev + 1 : 0);
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
if (key.return) {
|
|
3518
|
+
const row = flattenedRows[selectedIndex];
|
|
3519
|
+
if (row?.kind === "project") {
|
|
3520
|
+
const k = projectKey(row.project);
|
|
3521
|
+
const next = new Set(expanded);
|
|
3522
|
+
if (next.has(k)) {
|
|
3523
|
+
next.delete(k);
|
|
3524
|
+
} else {
|
|
3525
|
+
next.add(k);
|
|
3526
|
+
refreshTasksForProject(row.project);
|
|
3527
|
+
}
|
|
3528
|
+
setExpanded(next);
|
|
3191
3529
|
}
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3530
|
+
return;
|
|
3531
|
+
}
|
|
3532
|
+
if (input === "s") {
|
|
3533
|
+
const row = flattenedRows[selectedIndex];
|
|
3534
|
+
if (row?.kind === "task") {
|
|
3535
|
+
setErrorLine(null);
|
|
3536
|
+
const desired = nextStatus(row.task.status);
|
|
3537
|
+
const result = updateTaskStatus(row.project, row.task.task_slug, desired);
|
|
3538
|
+
if (!result.ok) {
|
|
3539
|
+
setErrorLine(`Failed to update status: ${result.error}`);
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
setTaskCache((prev) => {
|
|
3543
|
+
const k = projectKey(row.project);
|
|
3544
|
+
const tasks = prev[k] || [];
|
|
3545
|
+
const updated = tasks.map((t) => t.task_slug === row.task.task_slug ? result.meta : t);
|
|
3546
|
+
return { ...prev, [k]: updated };
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3196
3551
|
}
|
|
3197
3552
|
});
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
(
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3553
|
+
useEffect2(() => {
|
|
3554
|
+
setSelectedIndex((prev) => {
|
|
3555
|
+
if (flattenedRows.length === 0) return 0;
|
|
3556
|
+
return Math.min(prev, flattenedRows.length - 1);
|
|
3557
|
+
});
|
|
3558
|
+
}, [mode, allProjects, expanded, taskCache]);
|
|
3559
|
+
const projectItems = useMemo2(() => {
|
|
3560
|
+
return allProjects.map((p) => {
|
|
3561
|
+
const projectConfig = config.projects.find(
|
|
3562
|
+
(c) => c.path && c.path === p.path || p.source === "global" && c.name === p.name || !c.path && c.name === p.name
|
|
3563
|
+
);
|
|
3564
|
+
const isExposed = projectConfig ? projectConfig.expose : config.defaults.includeNew;
|
|
3565
|
+
return {
|
|
3566
|
+
label: formatProjectLabel(p),
|
|
3567
|
+
value: p.path,
|
|
3568
|
+
key: p.path,
|
|
3569
|
+
exposed: isExposed
|
|
3570
|
+
};
|
|
3571
|
+
});
|
|
3572
|
+
}, [allProjects, config]);
|
|
3573
|
+
const initialSelected = useMemo2(() => {
|
|
3574
|
+
return projectItems.filter((p) => p.exposed).map((p) => p.value);
|
|
3575
|
+
}, [projectItems]);
|
|
3212
3576
|
const handleSubmit = (selectedIds) => {
|
|
3213
3577
|
let newConfig = { ...config };
|
|
3214
3578
|
projectItems.forEach((item) => {
|
|
@@ -3228,33 +3592,135 @@ var init_ProjectsView = __esm({
|
|
|
3228
3592
|
});
|
|
3229
3593
|
saveMCPConfig(newConfig);
|
|
3230
3594
|
setConfig(newConfig);
|
|
3231
|
-
|
|
3595
|
+
onConfigChange?.();
|
|
3232
3596
|
};
|
|
3597
|
+
const flattenedRows = useMemo2(() => {
|
|
3598
|
+
const rows = [];
|
|
3599
|
+
for (const p of sortedProjects) {
|
|
3600
|
+
rows.push({ kind: "project", project: p });
|
|
3601
|
+
const k = projectKey(p);
|
|
3602
|
+
if (!expanded.has(k)) continue;
|
|
3603
|
+
const tasks = taskCache[k] || [];
|
|
3604
|
+
for (const t of tasks) {
|
|
3605
|
+
rows.push({ kind: "task", project: p, task: t });
|
|
3606
|
+
}
|
|
3607
|
+
if ((taskCache[k] || []).length === 0) {
|
|
3608
|
+
rows.push({ kind: "task", project: p, task: { task_slug: "__none__", title: "(no tasks)", status: "" } });
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
return rows;
|
|
3612
|
+
}, [sortedProjects, expanded, taskCache]);
|
|
3613
|
+
const selectedRow = flattenedRows[selectedIndex];
|
|
3614
|
+
const selectedTask = selectedRow?.kind === "task" && selectedRow.task.task_slug !== "__none__" ? selectedRow.task : null;
|
|
3615
|
+
if (mode === "expose") {
|
|
3616
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan", flexGrow: 1, children: [
|
|
3617
|
+
/* @__PURE__ */ jsxs3(Box4, { justifyContent: "space-between", children: [
|
|
3618
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: " Projects (Expose Mode) " }),
|
|
3619
|
+
/* @__PURE__ */ jsxs3(Box4, { children: [
|
|
3620
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Auto-expose new: " }),
|
|
3621
|
+
/* @__PURE__ */ jsx4(Text4, { color: config.defaults.includeNew ? "green" : "red", children: config.defaults.includeNew ? "ON" : "OFF" }),
|
|
3622
|
+
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " (Press 'a' to toggle)" })
|
|
3623
|
+
] })
|
|
3624
|
+
] }),
|
|
3625
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: " Space toggles, Enter saves. Press 't' to switch to Tasks Mode." }),
|
|
3626
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx4(
|
|
3627
|
+
SimpleSelect,
|
|
3628
|
+
{
|
|
3629
|
+
message: "",
|
|
3630
|
+
items: projectItems,
|
|
3631
|
+
isMulti: true,
|
|
3632
|
+
initialSelected,
|
|
3633
|
+
onSelect: () => {
|
|
3634
|
+
},
|
|
3635
|
+
onSubmit: handleSubmit,
|
|
3636
|
+
onCancel: () => {
|
|
3637
|
+
}
|
|
3638
|
+
},
|
|
3639
|
+
JSON.stringify(initialSelected) + config.defaults.includeNew
|
|
3640
|
+
) })
|
|
3641
|
+
] });
|
|
3642
|
+
}
|
|
3233
3643
|
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: "cyan", flexGrow: 1, children: [
|
|
3234
3644
|
/* @__PURE__ */ jsxs3(Box4, { justifyContent: "space-between", children: [
|
|
3235
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "
|
|
3236
|
-
/* @__PURE__ */
|
|
3237
|
-
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Auto-expose new: " }),
|
|
3238
|
-
/* @__PURE__ */ jsx4(Text4, { color: config.defaults.includeNew ? "green" : "red", children: config.defaults.includeNew ? "ON" : "OFF" }),
|
|
3239
|
-
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " (Press 'a' to toggle)" })
|
|
3240
|
-
] })
|
|
3645
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: " Projects (Tasks Mode) " }),
|
|
3646
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: "t:Expose Enter:Expand s:Status R:Refresh" })
|
|
3241
3647
|
] }),
|
|
3242
|
-
/* @__PURE__ */ jsx4(
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3648
|
+
errorLine && /* @__PURE__ */ jsx4(Box4, { marginTop: 0, children: /* @__PURE__ */ jsx4(Text4, { color: "red", children: errorLine }) }),
|
|
3649
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "row", flexGrow: 1, children: [
|
|
3650
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", width: "55%", children: [
|
|
3651
|
+
flattenedRows.length === 0 ? /* @__PURE__ */ jsx4(Text4, { color: "dim", children: "No projects detected." }) : flattenedRows.map((row, idx) => {
|
|
3652
|
+
const isSel = idx === selectedIndex;
|
|
3653
|
+
if (row.kind === "project") {
|
|
3654
|
+
const k = projectKey(row.project);
|
|
3655
|
+
const isOpen = expanded.has(k);
|
|
3656
|
+
const count = (taskCache[k] || []).length;
|
|
3657
|
+
return /* @__PURE__ */ jsxs3(Box4, { children: [
|
|
3658
|
+
/* @__PURE__ */ jsx4(Text4, { color: isSel ? "cyan" : "white", children: isSel ? "> " : " " }),
|
|
3659
|
+
/* @__PURE__ */ jsxs3(Text4, { color: isSel ? "cyan" : "white", children: [
|
|
3660
|
+
isOpen ? "\u25BE " : "\u25B8 ",
|
|
3661
|
+
formatProjectLabel(row.project)
|
|
3662
|
+
] }),
|
|
3663
|
+
/* @__PURE__ */ jsxs3(Text4, { color: "dim", children: [
|
|
3664
|
+
" ",
|
|
3665
|
+
count > 0 ? ` (tasks: ${count})` : ""
|
|
3666
|
+
] })
|
|
3667
|
+
] }, `p:${k}`);
|
|
3668
|
+
}
|
|
3669
|
+
const taskLabel = row.task.title || row.task.task_slug;
|
|
3670
|
+
const status = row.task.status || "";
|
|
3671
|
+
return /* @__PURE__ */ jsxs3(Box4, { children: [
|
|
3672
|
+
/* @__PURE__ */ jsx4(Text4, { color: isSel ? "cyan" : "white", children: isSel ? "> " : " " }),
|
|
3673
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: " - " }),
|
|
3674
|
+
/* @__PURE__ */ jsx4(Text4, { color: isSel ? "cyan" : "white", children: taskLabel }),
|
|
3675
|
+
row.task.task_slug !== "__none__" && /* @__PURE__ */ jsx4(Text4, { color: status === "complete" ? "green" : status === "blocked" ? "red" : "yellow", children: ` [${status}]` })
|
|
3676
|
+
] }, `t:${projectKey(row.project)}:${row.task.task_slug}`);
|
|
3677
|
+
}),
|
|
3678
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "\u25B2/\u25BC navigate \u2022 Enter expand/collapse \u2022 s cycle status \u2022 R refresh \u2022 t expose mode" }) })
|
|
3679
|
+
] }),
|
|
3680
|
+
/* @__PURE__ */ jsx4(Box4, { flexDirection: "column", width: "45%", paddingLeft: 2, children: !selectedTask ? /* @__PURE__ */ jsx4(Text4, { color: "dim", children: "Select a task to view details." }) : /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
|
|
3681
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: selectedTask.title || selectedTask.task_slug }),
|
|
3682
|
+
selectedTask.summary && /* @__PURE__ */ jsx4(Text4, { children: selectedTask.summary }),
|
|
3683
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
3684
|
+
/* @__PURE__ */ jsxs3(Text4, { children: [
|
|
3685
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: "Status: " }),
|
|
3686
|
+
/* @__PURE__ */ jsx4(Text4, { children: selectedTask.status || "unknown" })
|
|
3687
|
+
] }),
|
|
3688
|
+
/* @__PURE__ */ jsxs3(Text4, { children: [
|
|
3689
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: "Updated: " }),
|
|
3690
|
+
/* @__PURE__ */ jsx4(Text4, { children: selectedTask.updated_at || "\u2014" })
|
|
3691
|
+
] }),
|
|
3692
|
+
/* @__PURE__ */ jsxs3(Text4, { children: [
|
|
3693
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: "Tags: " }),
|
|
3694
|
+
/* @__PURE__ */ jsx4(Text4, { children: (selectedTask.tags || []).join(", ") || "\u2014" })
|
|
3695
|
+
] })
|
|
3696
|
+
] }),
|
|
3697
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
3698
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, children: "Checklist" }),
|
|
3699
|
+
(selectedTask.checklist || []).length === 0 ? /* @__PURE__ */ jsx4(Text4, { color: "dim", children: "\u2014" }) : (selectedTask.checklist || []).slice(0, 12).map((c, i) => /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
3700
|
+
/* @__PURE__ */ jsx4(Text4, { color: "dim", children: "- " }),
|
|
3701
|
+
c.label || c.id || "item",
|
|
3702
|
+
" ",
|
|
3703
|
+
/* @__PURE__ */ jsxs3(Text4, { color: "dim", children: [
|
|
3704
|
+
"[",
|
|
3705
|
+
c.status || "pending",
|
|
3706
|
+
"]"
|
|
3707
|
+
] })
|
|
3708
|
+
] }, c.id || i))
|
|
3709
|
+
] }),
|
|
3710
|
+
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
3711
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, children: "Agents" }),
|
|
3712
|
+
!selectedTask.agents ? /* @__PURE__ */ jsx4(Text4, { color: "dim", children: "\u2014" }) : Object.entries(selectedTask.agents).map(([agent, info]) => /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
3713
|
+
/* @__PURE__ */ jsxs3(Text4, { color: "dim", children: [
|
|
3714
|
+
"- ",
|
|
3715
|
+
agent,
|
|
3716
|
+
": "
|
|
3717
|
+
] }),
|
|
3718
|
+
info?.status || "\u2014",
|
|
3719
|
+
info?.artifact ? ` (${info.artifact})` : ""
|
|
3720
|
+
] }, agent))
|
|
3721
|
+
] })
|
|
3722
|
+
] }) })
|
|
3723
|
+
] })
|
|
3258
3724
|
] });
|
|
3259
3725
|
};
|
|
3260
3726
|
}
|
|
@@ -3433,20 +3899,21 @@ var init_StatusBoard = __esm({
|
|
|
3433
3899
|
});
|
|
3434
3900
|
|
|
3435
3901
|
// src/mcp/ui/IndexingStatus.tsx
|
|
3436
|
-
import { useState as useState4, useEffect as
|
|
3902
|
+
import { useState as useState4, useEffect as useEffect4 } from "react";
|
|
3437
3903
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
3438
3904
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3439
3905
|
var IndexingStatus;
|
|
3440
3906
|
var init_IndexingStatus = __esm({
|
|
3441
3907
|
"src/mcp/ui/IndexingStatus.tsx"() {
|
|
3442
3908
|
"use strict";
|
|
3909
|
+
init_indexing_jobs();
|
|
3443
3910
|
init_rag();
|
|
3444
3911
|
init_resources();
|
|
3445
3912
|
init_config_utils();
|
|
3446
3913
|
IndexingStatus = ({ projects, config }) => {
|
|
3447
3914
|
const [stats, setStats] = useState4([]);
|
|
3448
3915
|
const [loading, setLoading] = useState4(true);
|
|
3449
|
-
|
|
3916
|
+
useEffect4(() => {
|
|
3450
3917
|
const fetchStats = async () => {
|
|
3451
3918
|
const newStats = [];
|
|
3452
3919
|
for (const project of projects) {
|
|
@@ -3456,9 +3923,14 @@ var init_IndexingStatus = __esm({
|
|
|
3456
3923
|
}
|
|
3457
3924
|
const enabled = projConfig?.semanticSearch?.enabled || project.semanticSearchEnabled || false;
|
|
3458
3925
|
if (!enabled) {
|
|
3926
|
+
const prog = indexingJobs.getProgress(project.name);
|
|
3459
3927
|
newStats.push({
|
|
3460
3928
|
projectName: project.name,
|
|
3461
3929
|
enabled: false,
|
|
3930
|
+
state: prog.state,
|
|
3931
|
+
itemsDone: prog.itemsDone,
|
|
3932
|
+
itemsTotal: prog.itemsTotal,
|
|
3933
|
+
currentItem: prog.currentItem,
|
|
3462
3934
|
totalFiles: 0,
|
|
3463
3935
|
totalChunks: 0
|
|
3464
3936
|
});
|
|
@@ -3468,17 +3940,27 @@ var init_IndexingStatus = __esm({
|
|
|
3468
3940
|
const indexPath = getRAGIndexPath(project);
|
|
3469
3941
|
const rag = new RAGService(indexPath, "dummy");
|
|
3470
3942
|
const s = rag.getStats();
|
|
3943
|
+
const prog = indexingJobs.getProgress(project.name);
|
|
3471
3944
|
newStats.push({
|
|
3472
3945
|
projectName: project.name,
|
|
3473
3946
|
enabled: true,
|
|
3947
|
+
state: prog.state,
|
|
3948
|
+
itemsDone: prog.itemsDone,
|
|
3949
|
+
itemsTotal: prog.itemsTotal,
|
|
3950
|
+
currentItem: prog.currentItem,
|
|
3474
3951
|
totalFiles: s.totalFiles,
|
|
3475
3952
|
totalChunks: s.totalChunks,
|
|
3476
3953
|
lastFullIndex: s.lastFullIndex
|
|
3477
3954
|
});
|
|
3478
3955
|
} catch (e) {
|
|
3956
|
+
const prog = indexingJobs.getProgress(project.name);
|
|
3479
3957
|
newStats.push({
|
|
3480
3958
|
projectName: project.name,
|
|
3481
3959
|
enabled: true,
|
|
3960
|
+
state: prog.state,
|
|
3961
|
+
itemsDone: prog.itemsDone,
|
|
3962
|
+
itemsTotal: prog.itemsTotal,
|
|
3963
|
+
currentItem: prog.currentItem,
|
|
3482
3964
|
totalFiles: 0,
|
|
3483
3965
|
totalChunks: 0,
|
|
3484
3966
|
error: String(e)
|
|
@@ -3501,13 +3983,16 @@ var init_IndexingStatus = __esm({
|
|
|
3501
3983
|
/* @__PURE__ */ jsxs8(Box9, { children: [
|
|
3502
3984
|
/* @__PURE__ */ jsx9(Box9, { width: 25, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Project" }) }),
|
|
3503
3985
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Status" }) }),
|
|
3986
|
+
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "State" }) }),
|
|
3987
|
+
/* @__PURE__ */ jsx9(Box9, { width: 18, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Progress" }) }),
|
|
3504
3988
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Indexed Files" }) }),
|
|
3505
3989
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Total Chunks" }) }),
|
|
3506
3990
|
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text9, { underline: true, children: "Last Index" }) })
|
|
3507
3991
|
] }),
|
|
3508
3992
|
stats.length === 0 ? /* @__PURE__ */ jsx9(Text9, { color: "dim", children: "No exposed projects found." }) : stats.map((s) => /* @__PURE__ */ jsxs8(Box9, { marginTop: 0, children: [
|
|
3509
3993
|
/* @__PURE__ */ jsx9(Box9, { width: 25, children: /* @__PURE__ */ jsx9(Text9, { color: "white", children: s.projectName }) }),
|
|
3510
|
-
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { color: s.enabled ? "green" : "dim", children: s.enabled ?
|
|
3994
|
+
/* @__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" }) }),
|
|
3995
|
+
/* @__PURE__ */ jsx9(Box9, { width: 18, children: /* @__PURE__ */ jsx9(Text9, { children: s.state === "running" ? `${s.itemsDone}/${s.itemsTotal ?? "?"}` : "-" }) }),
|
|
3511
3996
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { children: s.enabled ? s.totalFiles : "-" }) }),
|
|
3512
3997
|
/* @__PURE__ */ jsx9(Box9, { width: 15, children: /* @__PURE__ */ jsx9(Text9, { children: s.enabled ? s.totalChunks : "-" }) }),
|
|
3513
3998
|
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text9, { children: s.lastFullIndex ? new Date(s.lastFullIndex).toLocaleTimeString() : "-" }) })
|
|
@@ -3573,9 +4058,9 @@ var App_exports = {};
|
|
|
3573
4058
|
__export(App_exports, {
|
|
3574
4059
|
App: () => App
|
|
3575
4060
|
});
|
|
3576
|
-
import { useState as useState5, useEffect as
|
|
4061
|
+
import { useState as useState5, useEffect as useEffect5, useMemo as useMemo3, useCallback } from "react";
|
|
3577
4062
|
import { Box as Box11, useInput as useInput4, useApp } from "ink";
|
|
3578
|
-
import
|
|
4063
|
+
import fs17 from "fs";
|
|
3579
4064
|
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3580
4065
|
var App;
|
|
3581
4066
|
var init_App = __esm({
|
|
@@ -3611,17 +4096,17 @@ var init_App = __esm({
|
|
|
3611
4096
|
setConfig(loadMCPConfig());
|
|
3612
4097
|
setProjects(scanForProjects());
|
|
3613
4098
|
}, []);
|
|
3614
|
-
const exposedProjects =
|
|
4099
|
+
const exposedProjects = useMemo3(
|
|
3615
4100
|
() => projects.filter((p) => isProjectExposed(config, p.name, p.path)),
|
|
3616
4101
|
[projects, config]
|
|
3617
4102
|
);
|
|
3618
|
-
const isRAGEnabled =
|
|
4103
|
+
const isRAGEnabled = useMemo3(() => {
|
|
3619
4104
|
return exposedProjects.some((p) => {
|
|
3620
4105
|
const cfg = findProjectConfig(config, { name: p.name, path: p.path });
|
|
3621
4106
|
return cfg?.semanticSearch?.enabled || p.semanticSearchEnabled;
|
|
3622
4107
|
});
|
|
3623
4108
|
}, [exposedProjects, config]);
|
|
3624
|
-
const tabs =
|
|
4109
|
+
const tabs = useMemo3(() => {
|
|
3625
4110
|
const baseTabs = [
|
|
3626
4111
|
{ id: "overview", label: "Overview" },
|
|
3627
4112
|
{ id: "logs", label: "Logs" },
|
|
@@ -3641,7 +4126,7 @@ var init_App = __esm({
|
|
|
3641
4126
|
installStatus.vscodeGlobal,
|
|
3642
4127
|
installStatus.vscodeWorkspace
|
|
3643
4128
|
].filter(Boolean).length;
|
|
3644
|
-
|
|
4129
|
+
useEffect5(() => {
|
|
3645
4130
|
const start = async () => {
|
|
3646
4131
|
const status = getMCPServerStatus();
|
|
3647
4132
|
if (!status.running) {
|
|
@@ -3657,21 +4142,21 @@ var init_App = __esm({
|
|
|
3657
4142
|
};
|
|
3658
4143
|
start();
|
|
3659
4144
|
}, []);
|
|
3660
|
-
|
|
4145
|
+
useEffect5(() => {
|
|
3661
4146
|
const logPath = getLogFilePath();
|
|
3662
4147
|
let lastSize = 0;
|
|
3663
|
-
if (
|
|
3664
|
-
const stats =
|
|
4148
|
+
if (fs17.existsSync(logPath)) {
|
|
4149
|
+
const stats = fs17.statSync(logPath);
|
|
3665
4150
|
lastSize = stats.size;
|
|
3666
4151
|
}
|
|
3667
4152
|
const interval = setInterval(() => {
|
|
3668
|
-
if (
|
|
3669
|
-
const stats =
|
|
4153
|
+
if (fs17.existsSync(logPath)) {
|
|
4154
|
+
const stats = fs17.statSync(logPath);
|
|
3670
4155
|
if (stats.size > lastSize) {
|
|
3671
4156
|
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
3672
|
-
const fd =
|
|
3673
|
-
|
|
3674
|
-
|
|
4157
|
+
const fd = fs17.openSync(logPath, "r");
|
|
4158
|
+
fs17.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
4159
|
+
fs17.closeSync(fd);
|
|
3675
4160
|
const newContent = buffer.toString("utf-8");
|
|
3676
4161
|
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
3677
4162
|
setLogs((prev) => {
|
|
@@ -3882,7 +4367,7 @@ var init_mcp = __esm({
|
|
|
3882
4367
|
// src/commands/wizard/index.ts
|
|
3883
4368
|
import { intro as intro2, select as select5, spinner as spinner7, note as note11, outro as outro7, isCancel as isCancel12 } from "@clack/prompts";
|
|
3884
4369
|
import pc13 from "picocolors";
|
|
3885
|
-
import * as
|
|
4370
|
+
import * as fs22 from "fs";
|
|
3886
4371
|
|
|
3887
4372
|
// src/lib/git.ts
|
|
3888
4373
|
import { execSync } from "child_process";
|
|
@@ -4556,7 +5041,7 @@ async function handlePostSetup(config, workspacePath, workspaceName, linkedProje
|
|
|
4556
5041
|
init_paths();
|
|
4557
5042
|
import { multiselect as multiselect4, spinner as spinner3, note as note7, outro as outro3, cancel as cancel3, isCancel as isCancel8, confirm as confirm6 } from "@clack/prompts";
|
|
4558
5043
|
import pc9 from "picocolors";
|
|
4559
|
-
import * as
|
|
5044
|
+
import * as fs18 from "fs";
|
|
4560
5045
|
init_detection();
|
|
4561
5046
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
4562
5047
|
const projects = scanForProjects({
|
|
@@ -4595,7 +5080,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
4595
5080
|
const s = spinner3();
|
|
4596
5081
|
s.start("Linking projects");
|
|
4597
5082
|
const configFilePath = getConfigPath(workspacePath);
|
|
4598
|
-
let configContent =
|
|
5083
|
+
let configContent = fs18.readFileSync(configFilePath, "utf-8");
|
|
4599
5084
|
if (configContent.includes("linked_projects:")) {
|
|
4600
5085
|
const lines = configContent.split("\n");
|
|
4601
5086
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -4622,7 +5107,7 @@ linked_projects:
|
|
|
4622
5107
|
`;
|
|
4623
5108
|
});
|
|
4624
5109
|
}
|
|
4625
|
-
|
|
5110
|
+
fs18.writeFileSync(configFilePath, configContent);
|
|
4626
5111
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
4627
5112
|
s.stop("Projects linked");
|
|
4628
5113
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
@@ -4657,15 +5142,15 @@ linked_projects:
|
|
|
4657
5142
|
init_paths();
|
|
4658
5143
|
import { confirm as confirm7, spinner as spinner4, note as note8, outro as outro4, cancel as cancel4, isCancel as isCancel9 } from "@clack/prompts";
|
|
4659
5144
|
import pc10 from "picocolors";
|
|
4660
|
-
import * as
|
|
4661
|
-
import * as
|
|
5145
|
+
import * as fs19 from "fs";
|
|
5146
|
+
import * as path19 from "path";
|
|
4662
5147
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
4663
5148
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
4664
5149
|
const customGlobalPath = getEffectiveRRCEHome(workspacePath);
|
|
4665
|
-
const globalPath =
|
|
5150
|
+
const globalPath = path19.join(customGlobalPath, "workspaces", workspaceName);
|
|
4666
5151
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
4667
5152
|
const existingDirs = subdirs.filter(
|
|
4668
|
-
(dir) =>
|
|
5153
|
+
(dir) => fs19.existsSync(path19.join(localPath, dir))
|
|
4669
5154
|
);
|
|
4670
5155
|
if (existingDirs.length === 0) {
|
|
4671
5156
|
outro4(pc10.yellow("No data found in workspace storage to sync."));
|
|
@@ -4691,8 +5176,8 @@ Destination: ${pc10.cyan(globalPath)}`,
|
|
|
4691
5176
|
try {
|
|
4692
5177
|
ensureDir(globalPath);
|
|
4693
5178
|
for (const dir of existingDirs) {
|
|
4694
|
-
const srcDir =
|
|
4695
|
-
const destDir =
|
|
5179
|
+
const srcDir = path19.join(localPath, dir);
|
|
5180
|
+
const destDir = path19.join(globalPath, dir);
|
|
4696
5181
|
ensureDir(destDir);
|
|
4697
5182
|
copyDirRecursive(srcDir, destDir);
|
|
4698
5183
|
}
|
|
@@ -4719,8 +5204,8 @@ init_paths();
|
|
|
4719
5204
|
init_prompts();
|
|
4720
5205
|
import { confirm as confirm8, spinner as spinner5, note as note9, outro as outro5, cancel as cancel5, isCancel as isCancel10 } from "@clack/prompts";
|
|
4721
5206
|
import pc11 from "picocolors";
|
|
4722
|
-
import * as
|
|
4723
|
-
import * as
|
|
5207
|
+
import * as fs20 from "fs";
|
|
5208
|
+
import * as path20 from "path";
|
|
4724
5209
|
import { stringify as stringify3 } from "yaml";
|
|
4725
5210
|
init_install();
|
|
4726
5211
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
@@ -4740,8 +5225,8 @@ async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
|
4740
5225
|
];
|
|
4741
5226
|
const configFilePath = getConfigPath(workspacePath);
|
|
4742
5227
|
const ideTargets = [];
|
|
4743
|
-
if (
|
|
4744
|
-
const configContent =
|
|
5228
|
+
if (fs20.existsSync(configFilePath)) {
|
|
5229
|
+
const configContent = fs20.readFileSync(configFilePath, "utf-8");
|
|
4745
5230
|
if (configContent.includes("opencode: true")) ideTargets.push("OpenCode agents");
|
|
4746
5231
|
if (configContent.includes("copilot: true")) ideTargets.push("GitHub Copilot");
|
|
4747
5232
|
if (configContent.includes("antigravity: true")) ideTargets.push("Antigravity");
|
|
@@ -4767,17 +5252,17 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
4767
5252
|
}
|
|
4768
5253
|
s.start("Updating from package");
|
|
4769
5254
|
for (const dataPath of dataPaths) {
|
|
4770
|
-
copyDirToAllStoragePaths(
|
|
4771
|
-
copyDirToAllStoragePaths(
|
|
4772
|
-
copyDirToAllStoragePaths(
|
|
5255
|
+
copyDirToAllStoragePaths(path20.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
5256
|
+
copyDirToAllStoragePaths(path20.join(agentCoreDir, "prompts"), "prompts", [dataPath]);
|
|
5257
|
+
copyDirToAllStoragePaths(path20.join(agentCoreDir, "docs"), "docs", [dataPath]);
|
|
4773
5258
|
}
|
|
4774
5259
|
const rrceHome = customGlobalPath || getDefaultRRCEHome2();
|
|
4775
|
-
ensureDir(
|
|
4776
|
-
ensureDir(
|
|
4777
|
-
copyDirRecursive(
|
|
4778
|
-
copyDirRecursive(
|
|
4779
|
-
if (
|
|
4780
|
-
const configContent =
|
|
5260
|
+
ensureDir(path20.join(rrceHome, "templates"));
|
|
5261
|
+
ensureDir(path20.join(rrceHome, "docs"));
|
|
5262
|
+
copyDirRecursive(path20.join(agentCoreDir, "templates"), path20.join(rrceHome, "templates"));
|
|
5263
|
+
copyDirRecursive(path20.join(agentCoreDir, "docs"), path20.join(rrceHome, "docs"));
|
|
5264
|
+
if (fs20.existsSync(configFilePath)) {
|
|
5265
|
+
const configContent = fs20.readFileSync(configFilePath, "utf-8");
|
|
4781
5266
|
if (configContent.includes("copilot: true")) {
|
|
4782
5267
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
4783
5268
|
ensureDir(copilotPath);
|
|
@@ -4824,14 +5309,14 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
4824
5309
|
function updateOpenCodeAgents(prompts, mode, primaryDataPath) {
|
|
4825
5310
|
if (mode === "global") {
|
|
4826
5311
|
try {
|
|
4827
|
-
const promptsDir =
|
|
5312
|
+
const promptsDir = path20.join(path20.dirname(OPENCODE_CONFIG), "prompts");
|
|
4828
5313
|
ensureDir(promptsDir);
|
|
4829
5314
|
let opencodeConfig = { $schema: "https://opencode.ai/config.json" };
|
|
4830
|
-
if (
|
|
4831
|
-
opencodeConfig = JSON.parse(
|
|
5315
|
+
if (fs20.existsSync(OPENCODE_CONFIG)) {
|
|
5316
|
+
opencodeConfig = JSON.parse(fs20.readFileSync(OPENCODE_CONFIG, "utf-8"));
|
|
4832
5317
|
}
|
|
4833
5318
|
if (!opencodeConfig.agent) opencodeConfig.agent = {};
|
|
4834
|
-
const currentAgentNames = prompts.map((p) =>
|
|
5319
|
+
const currentAgentNames = prompts.map((p) => path20.basename(p.filePath, ".md"));
|
|
4835
5320
|
const existingAgentNames = Object.keys(opencodeConfig.agent);
|
|
4836
5321
|
const rrceAgentPrefixes = ["init", "research", "planning", "executor", "doctor", "documentation", "sync"];
|
|
4837
5322
|
for (const existingName of existingAgentNames) {
|
|
@@ -4839,30 +5324,30 @@ function updateOpenCodeAgents(prompts, mode, primaryDataPath) {
|
|
|
4839
5324
|
const stillExists = currentAgentNames.includes(existingName);
|
|
4840
5325
|
if (isRrceAgent && !stillExists) {
|
|
4841
5326
|
delete opencodeConfig.agent[existingName];
|
|
4842
|
-
const oldPromptFile =
|
|
4843
|
-
if (
|
|
4844
|
-
|
|
5327
|
+
const oldPromptFile = path20.join(promptsDir, `rrce-${existingName}.md`);
|
|
5328
|
+
if (fs20.existsSync(oldPromptFile)) {
|
|
5329
|
+
fs20.unlinkSync(oldPromptFile);
|
|
4845
5330
|
}
|
|
4846
5331
|
}
|
|
4847
5332
|
}
|
|
4848
5333
|
for (const prompt of prompts) {
|
|
4849
|
-
const baseName =
|
|
5334
|
+
const baseName = path20.basename(prompt.filePath, ".md");
|
|
4850
5335
|
const promptFileName = `rrce-${baseName}.md`;
|
|
4851
|
-
const promptFilePath =
|
|
4852
|
-
|
|
5336
|
+
const promptFilePath = path20.join(promptsDir, promptFileName);
|
|
5337
|
+
fs20.writeFileSync(promptFilePath, prompt.content);
|
|
4853
5338
|
const agentConfig = convertToOpenCodeAgent(prompt, true, `./prompts/${promptFileName}`);
|
|
4854
5339
|
opencodeConfig.agent[baseName] = agentConfig;
|
|
4855
5340
|
}
|
|
4856
|
-
|
|
5341
|
+
fs20.writeFileSync(OPENCODE_CONFIG, JSON.stringify(opencodeConfig, null, 2) + "\n");
|
|
4857
5342
|
} catch (e) {
|
|
4858
5343
|
console.error("Failed to update global OpenCode config with agents:", e);
|
|
4859
5344
|
}
|
|
4860
5345
|
} else {
|
|
4861
|
-
const opencodeBaseDir =
|
|
5346
|
+
const opencodeBaseDir = path20.join(primaryDataPath, ".opencode", "agent");
|
|
4862
5347
|
ensureDir(opencodeBaseDir);
|
|
4863
5348
|
clearDirectory(opencodeBaseDir);
|
|
4864
5349
|
for (const prompt of prompts) {
|
|
4865
|
-
const baseName =
|
|
5350
|
+
const baseName = path20.basename(prompt.filePath, ".md");
|
|
4866
5351
|
const agentConfig = convertToOpenCodeAgent(prompt);
|
|
4867
5352
|
const content = `---
|
|
4868
5353
|
${stringify3({
|
|
@@ -4871,22 +5356,22 @@ ${stringify3({
|
|
|
4871
5356
|
tools: agentConfig.tools
|
|
4872
5357
|
})}---
|
|
4873
5358
|
${agentConfig.prompt}`;
|
|
4874
|
-
|
|
5359
|
+
fs20.writeFileSync(path20.join(opencodeBaseDir, `${baseName}.md`), content);
|
|
4875
5360
|
}
|
|
4876
5361
|
}
|
|
4877
5362
|
}
|
|
4878
5363
|
function clearDirectory(dirPath) {
|
|
4879
|
-
if (!
|
|
4880
|
-
const entries =
|
|
5364
|
+
if (!fs20.existsSync(dirPath)) return;
|
|
5365
|
+
const entries = fs20.readdirSync(dirPath, { withFileTypes: true });
|
|
4881
5366
|
for (const entry of entries) {
|
|
4882
5367
|
if (entry.isFile()) {
|
|
4883
|
-
|
|
5368
|
+
fs20.unlinkSync(path20.join(dirPath, entry.name));
|
|
4884
5369
|
}
|
|
4885
5370
|
}
|
|
4886
5371
|
}
|
|
4887
5372
|
function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot, customGlobalPath) {
|
|
4888
|
-
const globalPath =
|
|
4889
|
-
const workspacePath =
|
|
5373
|
+
const globalPath = path20.join(customGlobalPath, "workspaces", workspaceName);
|
|
5374
|
+
const workspacePath = path20.join(workspaceRoot, ".rrce-workflow");
|
|
4890
5375
|
switch (mode) {
|
|
4891
5376
|
case "global":
|
|
4892
5377
|
return [globalPath];
|
|
@@ -4900,7 +5385,7 @@ function resolveAllDataPathsWithCustomGlobal(mode, workspaceName, workspaceRoot,
|
|
|
4900
5385
|
// src/commands/wizard/delete-flow.ts
|
|
4901
5386
|
import { multiselect as multiselect5, confirm as confirm9, spinner as spinner6, note as note10, cancel as cancel6, isCancel as isCancel11 } from "@clack/prompts";
|
|
4902
5387
|
import pc12 from "picocolors";
|
|
4903
|
-
import * as
|
|
5388
|
+
import * as fs21 from "fs";
|
|
4904
5389
|
init_detection();
|
|
4905
5390
|
init_config();
|
|
4906
5391
|
async function runDeleteGlobalProjectFlow(availableProjects) {
|
|
@@ -4944,8 +5429,8 @@ Are you sure?`,
|
|
|
4944
5429
|
for (const projectName of projectsToDelete) {
|
|
4945
5430
|
const project = globalProjects.find((p) => p.name === projectName);
|
|
4946
5431
|
if (!project) continue;
|
|
4947
|
-
if (
|
|
4948
|
-
|
|
5432
|
+
if (fs21.existsSync(project.dataPath)) {
|
|
5433
|
+
fs21.rmSync(project.dataPath, { recursive: true, force: true });
|
|
4949
5434
|
}
|
|
4950
5435
|
const newConfig = removeProjectConfig(mcpConfig, projectName);
|
|
4951
5436
|
configChanged = true;
|
|
@@ -4991,11 +5476,11 @@ Workspace: ${pc13.bold(workspaceName)}`,
|
|
|
4991
5476
|
workspacePath
|
|
4992
5477
|
});
|
|
4993
5478
|
const configFilePath = getConfigPath(workspacePath);
|
|
4994
|
-
let isAlreadyConfigured =
|
|
5479
|
+
let isAlreadyConfigured = fs22.existsSync(configFilePath);
|
|
4995
5480
|
let currentStorageMode = null;
|
|
4996
5481
|
if (isAlreadyConfigured) {
|
|
4997
5482
|
try {
|
|
4998
|
-
const configContent =
|
|
5483
|
+
const configContent = fs22.readFileSync(configFilePath, "utf-8");
|
|
4999
5484
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
5000
5485
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
5001
5486
|
} catch {
|
|
@@ -5012,7 +5497,7 @@ Workspace: ${pc13.bold(workspaceName)}`,
|
|
|
5012
5497
|
}
|
|
5013
5498
|
}
|
|
5014
5499
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
5015
|
-
const hasLocalData =
|
|
5500
|
+
const hasLocalData = fs22.existsSync(localDataPath);
|
|
5016
5501
|
if (isAlreadyConfigured) {
|
|
5017
5502
|
const menuOptions = [];
|
|
5018
5503
|
menuOptions.push({
|