rrce-workflow 0.2.29 → 0.2.30
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 +295 -162
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -721,6 +721,17 @@ var init_types = __esm({
|
|
|
721
721
|
});
|
|
722
722
|
|
|
723
723
|
// src/mcp/config.ts
|
|
724
|
+
var config_exports = {};
|
|
725
|
+
__export(config_exports, {
|
|
726
|
+
ensureMCPGlobalPath: () => ensureMCPGlobalPath,
|
|
727
|
+
getMCPConfigPath: () => getMCPConfigPath,
|
|
728
|
+
getProjectPermissions: () => getProjectPermissions,
|
|
729
|
+
isProjectExposed: () => isProjectExposed,
|
|
730
|
+
loadMCPConfig: () => loadMCPConfig,
|
|
731
|
+
removeProjectConfig: () => removeProjectConfig,
|
|
732
|
+
saveMCPConfig: () => saveMCPConfig,
|
|
733
|
+
setProjectConfig: () => setProjectConfig
|
|
734
|
+
});
|
|
724
735
|
import * as fs7 from "fs";
|
|
725
736
|
import * as path8 from "path";
|
|
726
737
|
function getMCPConfigPath() {
|
|
@@ -907,6 +918,10 @@ function setProjectConfig(config, name, expose, permissions) {
|
|
|
907
918
|
}
|
|
908
919
|
return config;
|
|
909
920
|
}
|
|
921
|
+
function removeProjectConfig(config, name) {
|
|
922
|
+
config.projects = config.projects.filter((p) => p.name !== name);
|
|
923
|
+
return config;
|
|
924
|
+
}
|
|
910
925
|
function isProjectExposed(config, name) {
|
|
911
926
|
const project = config.projects.find((p) => p.name === name);
|
|
912
927
|
if (project) {
|
|
@@ -1683,6 +1698,226 @@ var init_install = __esm({
|
|
|
1683
1698
|
}
|
|
1684
1699
|
});
|
|
1685
1700
|
|
|
1701
|
+
// src/mcp/ui/Header.tsx
|
|
1702
|
+
import "react";
|
|
1703
|
+
import { Box, Text } from "ink";
|
|
1704
|
+
import { jsx } from "react/jsx-runtime";
|
|
1705
|
+
var Header;
|
|
1706
|
+
var init_Header = __esm({
|
|
1707
|
+
"src/mcp/ui/Header.tsx"() {
|
|
1708
|
+
"use strict";
|
|
1709
|
+
Header = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingBottom: 1, children: /* @__PURE__ */ jsx(Box, { borderStyle: "double", borderColor: "cyan", paddingX: 2, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: " RRCE MCP Hub " }) }) });
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1713
|
+
// src/mcp/ui/StatusBoard.tsx
|
|
1714
|
+
import "react";
|
|
1715
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
1716
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
1717
|
+
var StatusBoard;
|
|
1718
|
+
var init_StatusBoard = __esm({
|
|
1719
|
+
"src/mcp/ui/StatusBoard.tsx"() {
|
|
1720
|
+
"use strict";
|
|
1721
|
+
StatusBoard = ({ exposedLabel, port, pid }) => {
|
|
1722
|
+
return /* @__PURE__ */ jsx2(Box2, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { children: [
|
|
1723
|
+
"\u{1F4CB} ",
|
|
1724
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: exposedLabel }),
|
|
1725
|
+
" ",
|
|
1726
|
+
"\u2502",
|
|
1727
|
+
" Port: ",
|
|
1728
|
+
/* @__PURE__ */ jsx2(Text2, { color: "green", children: port }),
|
|
1729
|
+
" ",
|
|
1730
|
+
"\u2502",
|
|
1731
|
+
" PID: ",
|
|
1732
|
+
/* @__PURE__ */ jsx2(Text2, { color: "green", children: pid })
|
|
1733
|
+
] }) });
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
});
|
|
1737
|
+
|
|
1738
|
+
// src/mcp/ui/LogViewer.tsx
|
|
1739
|
+
import "react";
|
|
1740
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
1741
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1742
|
+
var LogViewer;
|
|
1743
|
+
var init_LogViewer = __esm({
|
|
1744
|
+
"src/mcp/ui/LogViewer.tsx"() {
|
|
1745
|
+
"use strict";
|
|
1746
|
+
LogViewer = ({ logs, height }) => {
|
|
1747
|
+
const visibleLogs = logs.slice(-height);
|
|
1748
|
+
const emptyLines = Math.max(0, height - visibleLogs.length);
|
|
1749
|
+
const padding = Array(emptyLines).fill("");
|
|
1750
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "dim", paddingX: 1, height: height + 2, flexGrow: 1, children: [
|
|
1751
|
+
padding.map((_, i) => /* @__PURE__ */ jsx3(Text3, { children: " " }, `empty-${i}`)),
|
|
1752
|
+
visibleLogs.map((log, i) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate-end", children: log }, `log-${i}`))
|
|
1753
|
+
] });
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
});
|
|
1757
|
+
|
|
1758
|
+
// src/mcp/ui/CommandBar.tsx
|
|
1759
|
+
import "react";
|
|
1760
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
1761
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1762
|
+
var CommandBar;
|
|
1763
|
+
var init_CommandBar = __esm({
|
|
1764
|
+
"src/mcp/ui/CommandBar.tsx"() {
|
|
1765
|
+
"use strict";
|
|
1766
|
+
CommandBar = () => {
|
|
1767
|
+
return /* @__PURE__ */ jsx4(Box4, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
1768
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "q" }),
|
|
1769
|
+
":Quit ",
|
|
1770
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "p" }),
|
|
1771
|
+
":Projects ",
|
|
1772
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "i" }),
|
|
1773
|
+
":Install ",
|
|
1774
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "r" }),
|
|
1775
|
+
":Reload ",
|
|
1776
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "c" }),
|
|
1777
|
+
":Clear ",
|
|
1778
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "?" }),
|
|
1779
|
+
":Help"
|
|
1780
|
+
] }) });
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1785
|
+
// src/mcp/ui/Dashboard.tsx
|
|
1786
|
+
import "react";
|
|
1787
|
+
import { Box as Box5 } from "ink";
|
|
1788
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1789
|
+
var Dashboard;
|
|
1790
|
+
var init_Dashboard = __esm({
|
|
1791
|
+
"src/mcp/ui/Dashboard.tsx"() {
|
|
1792
|
+
"use strict";
|
|
1793
|
+
init_Header();
|
|
1794
|
+
init_StatusBoard();
|
|
1795
|
+
init_LogViewer();
|
|
1796
|
+
init_CommandBar();
|
|
1797
|
+
Dashboard = ({ logs, exposedLabel, port, pid, logHeight }) => {
|
|
1798
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", padding: 0, children: [
|
|
1799
|
+
/* @__PURE__ */ jsx5(Header, {}),
|
|
1800
|
+
/* @__PURE__ */ jsx5(LogViewer, { logs, height: logHeight }),
|
|
1801
|
+
/* @__PURE__ */ jsx5(StatusBoard, { exposedLabel, port, pid }),
|
|
1802
|
+
/* @__PURE__ */ jsx5(CommandBar, {})
|
|
1803
|
+
] });
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
// src/mcp/ui/App.tsx
|
|
1809
|
+
var App_exports = {};
|
|
1810
|
+
__export(App_exports, {
|
|
1811
|
+
App: () => App
|
|
1812
|
+
});
|
|
1813
|
+
import { useState, useEffect as useEffect2 } from "react";
|
|
1814
|
+
import { useInput, useApp } from "ink";
|
|
1815
|
+
import fs11 from "fs";
|
|
1816
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1817
|
+
var App;
|
|
1818
|
+
var init_App = __esm({
|
|
1819
|
+
"src/mcp/ui/App.tsx"() {
|
|
1820
|
+
"use strict";
|
|
1821
|
+
init_Dashboard();
|
|
1822
|
+
init_config();
|
|
1823
|
+
init_detection();
|
|
1824
|
+
init_logger();
|
|
1825
|
+
init_server();
|
|
1826
|
+
App = ({ onExit, onConfigure, onInstall, initialPort }) => {
|
|
1827
|
+
const { exit } = useApp();
|
|
1828
|
+
const [logs, setLogs] = useState([]);
|
|
1829
|
+
const [serverInfo, setServerInfo] = useState({
|
|
1830
|
+
port: initialPort,
|
|
1831
|
+
pid: process.pid,
|
|
1832
|
+
running: false
|
|
1833
|
+
});
|
|
1834
|
+
const config = loadMCPConfig();
|
|
1835
|
+
const projects = scanForProjects();
|
|
1836
|
+
const exposedProjects = projects.filter((p) => {
|
|
1837
|
+
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1838
|
+
return cfg?.expose ?? config.defaults.includeNew;
|
|
1839
|
+
});
|
|
1840
|
+
const exposedNames = exposedProjects.map((p) => p.name).slice(0, 5);
|
|
1841
|
+
const exposedLabel = exposedNames.length > 0 ? exposedNames.join(", ") + (exposedProjects.length > 5 ? ` (+${exposedProjects.length - 5} more)` : "") : "(none)";
|
|
1842
|
+
useEffect2(() => {
|
|
1843
|
+
const start = async () => {
|
|
1844
|
+
const status = getMCPServerStatus();
|
|
1845
|
+
if (!status.running) {
|
|
1846
|
+
try {
|
|
1847
|
+
const res = await startMCPServer();
|
|
1848
|
+
setServerInfo((prev) => ({ ...prev, running: true, port: res.port, pid: res.pid }));
|
|
1849
|
+
} catch (e) {
|
|
1850
|
+
setLogs((prev) => [...prev, `Error starting server: ${e}`]);
|
|
1851
|
+
}
|
|
1852
|
+
} else {
|
|
1853
|
+
setServerInfo((prev) => ({ ...prev, running: true, port: status.port || initialPort, pid: status.pid || process.pid }));
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
start();
|
|
1857
|
+
return () => {
|
|
1858
|
+
};
|
|
1859
|
+
}, []);
|
|
1860
|
+
useEffect2(() => {
|
|
1861
|
+
const logPath = getLogFilePath();
|
|
1862
|
+
let lastSize = 0;
|
|
1863
|
+
if (fs11.existsSync(logPath)) {
|
|
1864
|
+
const stats = fs11.statSync(logPath);
|
|
1865
|
+
lastSize = stats.size;
|
|
1866
|
+
}
|
|
1867
|
+
const interval = setInterval(() => {
|
|
1868
|
+
if (fs11.existsSync(logPath)) {
|
|
1869
|
+
const stats = fs11.statSync(logPath);
|
|
1870
|
+
if (stats.size > lastSize) {
|
|
1871
|
+
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
1872
|
+
const fd = fs11.openSync(logPath, "r");
|
|
1873
|
+
fs11.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
1874
|
+
fs11.closeSync(fd);
|
|
1875
|
+
const newContent = buffer.toString("utf-8");
|
|
1876
|
+
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
1877
|
+
setLogs((prev) => {
|
|
1878
|
+
const next = [...prev, ...newLines];
|
|
1879
|
+
return next.slice(-50);
|
|
1880
|
+
});
|
|
1881
|
+
lastSize = stats.size;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
}, 500);
|
|
1885
|
+
return () => clearInterval(interval);
|
|
1886
|
+
}, []);
|
|
1887
|
+
useInput((input, key) => {
|
|
1888
|
+
if (input === "q" || key.ctrl && input === "c") {
|
|
1889
|
+
stopMCPServer();
|
|
1890
|
+
onExit();
|
|
1891
|
+
}
|
|
1892
|
+
if (input === "p") {
|
|
1893
|
+
onConfigure();
|
|
1894
|
+
}
|
|
1895
|
+
if (input === "i") {
|
|
1896
|
+
onInstall();
|
|
1897
|
+
}
|
|
1898
|
+
if (input === "c") {
|
|
1899
|
+
setLogs([]);
|
|
1900
|
+
}
|
|
1901
|
+
if (input === "r") {
|
|
1902
|
+
setLogs((prev) => [...prev, "[INFO] Config reload requested..."]);
|
|
1903
|
+
}
|
|
1904
|
+
});
|
|
1905
|
+
const termHeight = process.stdout.rows || 24;
|
|
1906
|
+
const logHeight = Math.max(5, termHeight - 12);
|
|
1907
|
+
return /* @__PURE__ */ jsx6(
|
|
1908
|
+
Dashboard,
|
|
1909
|
+
{
|
|
1910
|
+
logs,
|
|
1911
|
+
exposedLabel,
|
|
1912
|
+
port: serverInfo.port,
|
|
1913
|
+
pid: serverInfo.pid,
|
|
1914
|
+
logHeight
|
|
1915
|
+
}
|
|
1916
|
+
);
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
});
|
|
1920
|
+
|
|
1686
1921
|
// src/mcp/index.ts
|
|
1687
1922
|
var mcp_exports = {};
|
|
1688
1923
|
__export(mcp_exports, {
|
|
@@ -1694,9 +1929,13 @@ async function runMCP(subcommand2) {
|
|
|
1694
1929
|
if (subcommand2) {
|
|
1695
1930
|
switch (subcommand2) {
|
|
1696
1931
|
case "start":
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
}
|
|
1932
|
+
if (process.stdout.isTTY) {
|
|
1933
|
+
await handleStartServer();
|
|
1934
|
+
} else {
|
|
1935
|
+
await startMCPServer();
|
|
1936
|
+
await new Promise(() => {
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1700
1939
|
return;
|
|
1701
1940
|
case "stop":
|
|
1702
1941
|
await handleStopServer();
|
|
@@ -1848,9 +2087,11 @@ async function handleInstallWizard(workspacePath) {
|
|
|
1848
2087
|
}
|
|
1849
2088
|
}
|
|
1850
2089
|
async function handleStartServer() {
|
|
1851
|
-
const
|
|
1852
|
-
const {
|
|
1853
|
-
const
|
|
2090
|
+
const React7 = await import("react");
|
|
2091
|
+
const { render } = await import("ink");
|
|
2092
|
+
const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
|
|
2093
|
+
const { loadMCPConfig: loadMCPConfig2, saveMCPConfig: saveMCPConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2094
|
+
const config = loadMCPConfig2();
|
|
1854
2095
|
const projects = scanForProjects();
|
|
1855
2096
|
const exposedProjects = projects.filter((p) => {
|
|
1856
2097
|
const cfg = config.projects.find((c) => c.name === p.name);
|
|
@@ -1867,7 +2108,7 @@ async function handleStartServer() {
|
|
|
1867
2108
|
}
|
|
1868
2109
|
}
|
|
1869
2110
|
const status = getMCPServerStatus();
|
|
1870
|
-
let
|
|
2111
|
+
let initialPort = config.server.port;
|
|
1871
2112
|
if (!status.running) {
|
|
1872
2113
|
const portInput = await text({
|
|
1873
2114
|
message: "Select port for MCP Server",
|
|
@@ -1878,153 +2119,45 @@ async function handleStartServer() {
|
|
|
1878
2119
|
}
|
|
1879
2120
|
});
|
|
1880
2121
|
if (isCancel2(portInput)) return;
|
|
1881
|
-
newPort = parseInt(portInput, 10);
|
|
2122
|
+
const newPort = parseInt(portInput, 10);
|
|
1882
2123
|
if (newPort !== config.server.port) {
|
|
1883
2124
|
config.server.port = newPort;
|
|
1884
|
-
|
|
2125
|
+
saveMCPConfig2(config);
|
|
2126
|
+
initialPort = newPort;
|
|
1885
2127
|
}
|
|
1886
|
-
} else {
|
|
1887
|
-
newPort = status.port || newPort;
|
|
1888
|
-
note2(`Server is already running on port ${newPort}`, "Info");
|
|
1889
2128
|
}
|
|
1890
2129
|
console.clear();
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
};
|
|
1917
|
-
let logBuffer = [];
|
|
1918
|
-
render(logBuffer);
|
|
1919
|
-
try {
|
|
1920
|
-
if (!status.running) {
|
|
1921
|
-
await startMCPServer();
|
|
1922
|
-
}
|
|
1923
|
-
let lastSize = 0;
|
|
1924
|
-
if (fs16.existsSync(logPath)) {
|
|
1925
|
-
const stats = fs16.statSync(logPath);
|
|
1926
|
-
lastSize = stats.size;
|
|
1927
|
-
}
|
|
1928
|
-
let isRunning = true;
|
|
1929
|
-
let interval;
|
|
1930
|
-
if (process.stdin.setRawMode) {
|
|
1931
|
-
process.stdin.setRawMode(true);
|
|
1932
|
-
process.stdin.resume();
|
|
1933
|
-
process.stdin.setEncoding("utf8");
|
|
1934
|
-
}
|
|
1935
|
-
return new Promise((resolve) => {
|
|
1936
|
-
const cleanup = (shouldStopServer) => {
|
|
1937
|
-
isRunning = false;
|
|
1938
|
-
clearInterval(interval);
|
|
1939
|
-
if (process.stdin.setRawMode) {
|
|
1940
|
-
process.stdin.setRawMode(false);
|
|
1941
|
-
}
|
|
1942
|
-
process.stdin.removeListener("data", onKey);
|
|
1943
|
-
process.stdin.pause();
|
|
1944
|
-
if (shouldStopServer) {
|
|
1945
|
-
stopMCPServer();
|
|
1946
|
-
}
|
|
1947
|
-
console.log("");
|
|
1948
|
-
};
|
|
1949
|
-
const onKey = async (key) => {
|
|
1950
|
-
if (key === "" || key.toLowerCase() === "q") {
|
|
1951
|
-
cleanup(true);
|
|
1952
|
-
resolve();
|
|
1953
|
-
return;
|
|
1954
|
-
}
|
|
1955
|
-
if (key.toLowerCase() === "p") {
|
|
1956
|
-
cleanup(false);
|
|
1957
|
-
console.clear();
|
|
1958
|
-
await handleConfigure();
|
|
1959
|
-
await handleStartServer();
|
|
1960
|
-
resolve();
|
|
1961
|
-
return;
|
|
1962
|
-
}
|
|
1963
|
-
if (key.toLowerCase() === "i") {
|
|
1964
|
-
cleanup(false);
|
|
1965
|
-
console.clear();
|
|
1966
|
-
await handleInstallWizard(detectWorkspaceRoot());
|
|
1967
|
-
await handleStartServer();
|
|
1968
|
-
resolve();
|
|
1969
|
-
return;
|
|
1970
|
-
}
|
|
1971
|
-
if (key.toLowerCase() === "r") {
|
|
1972
|
-
logBuffer.push("[INFO] Reloading configuration...");
|
|
1973
|
-
render(logBuffer);
|
|
1974
|
-
return;
|
|
1975
|
-
}
|
|
1976
|
-
if (key.toLowerCase() === "c") {
|
|
1977
|
-
logBuffer = [];
|
|
1978
|
-
render(logBuffer);
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
if (key === "?") {
|
|
1982
|
-
logBuffer.push("\u2500".repeat(40));
|
|
1983
|
-
logBuffer.push("Commands:");
|
|
1984
|
-
logBuffer.push(" q - Stop server and return to menu");
|
|
1985
|
-
logBuffer.push(" p - Reconfigure exposed projects");
|
|
1986
|
-
logBuffer.push(" i - Install to additional IDEs");
|
|
1987
|
-
logBuffer.push(" r - Reload configuration");
|
|
1988
|
-
logBuffer.push(" c - Clear log display");
|
|
1989
|
-
logBuffer.push(" ? - Show this help");
|
|
1990
|
-
logBuffer.push("\u2500".repeat(40));
|
|
1991
|
-
render(logBuffer);
|
|
1992
|
-
return;
|
|
1993
|
-
}
|
|
1994
|
-
};
|
|
1995
|
-
process.stdin.on("data", onKey);
|
|
1996
|
-
interval = setInterval(() => {
|
|
1997
|
-
if (!isRunning) return;
|
|
1998
|
-
if (fs16.existsSync(logPath)) {
|
|
1999
|
-
const stats = fs16.statSync(logPath);
|
|
2000
|
-
if (stats.size > lastSize) {
|
|
2001
|
-
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
2002
|
-
const fd = fs16.openSync(logPath, "r");
|
|
2003
|
-
fs16.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
2004
|
-
fs16.closeSync(fd);
|
|
2005
|
-
const newContent = buffer.toString("utf-8");
|
|
2006
|
-
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
2007
|
-
logBuffer.push(...newLines);
|
|
2008
|
-
if (logBuffer.length > 100) {
|
|
2009
|
-
logBuffer = logBuffer.slice(-100);
|
|
2010
|
-
}
|
|
2011
|
-
lastSize = stats.size;
|
|
2012
|
-
render(logBuffer);
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
}, 500);
|
|
2016
|
-
});
|
|
2017
|
-
} catch (error) {
|
|
2018
|
-
if (process.stdin.setRawMode) {
|
|
2019
|
-
process.stdin.setRawMode(false);
|
|
2130
|
+
let keepRunning = true;
|
|
2131
|
+
while (keepRunning) {
|
|
2132
|
+
let nextAction = "exit";
|
|
2133
|
+
const app = render(React7.createElement(App2, {
|
|
2134
|
+
initialPort,
|
|
2135
|
+
onExit: () => {
|
|
2136
|
+
nextAction = "exit";
|
|
2137
|
+
},
|
|
2138
|
+
onConfigure: () => {
|
|
2139
|
+
nextAction = "configure";
|
|
2140
|
+
},
|
|
2141
|
+
onInstall: () => {
|
|
2142
|
+
nextAction = "install";
|
|
2143
|
+
}
|
|
2144
|
+
}));
|
|
2145
|
+
await app.waitUntilExit();
|
|
2146
|
+
if (nextAction === "exit") {
|
|
2147
|
+
keepRunning = false;
|
|
2148
|
+
} else if (nextAction === "configure") {
|
|
2149
|
+
console.clear();
|
|
2150
|
+
await handleConfigure();
|
|
2151
|
+
} else if (nextAction === "install") {
|
|
2152
|
+
console.clear();
|
|
2153
|
+
const workspacePath = detectWorkspaceRoot();
|
|
2154
|
+
await handleInstallWizard(workspacePath);
|
|
2020
2155
|
}
|
|
2021
|
-
console.error(pc3.red("\nFailed to start/monitor server:"));
|
|
2022
|
-
console.error(error);
|
|
2023
2156
|
}
|
|
2024
2157
|
}
|
|
2025
2158
|
async function handleConfigureGlobalPath() {
|
|
2026
2159
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
2027
|
-
const
|
|
2160
|
+
const fs17 = await import("fs");
|
|
2028
2161
|
const path16 = await import("path");
|
|
2029
2162
|
note2(
|
|
2030
2163
|
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
@@ -2039,8 +2172,8 @@ locally in each project. MCP needs a central location.`,
|
|
|
2039
2172
|
return false;
|
|
2040
2173
|
}
|
|
2041
2174
|
try {
|
|
2042
|
-
if (!
|
|
2043
|
-
|
|
2175
|
+
if (!fs17.existsSync(resolvedPath)) {
|
|
2176
|
+
fs17.mkdirSync(resolvedPath, { recursive: true });
|
|
2044
2177
|
}
|
|
2045
2178
|
const config = loadMCPConfig();
|
|
2046
2179
|
saveMCPConfig(config);
|
|
@@ -2220,7 +2353,7 @@ var init_mcp = __esm({
|
|
|
2220
2353
|
// src/commands/wizard/setup-flow.ts
|
|
2221
2354
|
import { group, select as select3, multiselect as multiselect2, confirm as confirm2, spinner as spinner2, note as note3, outro as outro2, cancel as cancel2, isCancel as isCancel3 } from "@clack/prompts";
|
|
2222
2355
|
import pc4 from "picocolors";
|
|
2223
|
-
import * as
|
|
2356
|
+
import * as fs12 from "fs";
|
|
2224
2357
|
import * as path12 from "path";
|
|
2225
2358
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
2226
2359
|
const s = spinner2();
|
|
@@ -2395,7 +2528,7 @@ linked_projects:
|
|
|
2395
2528
|
`;
|
|
2396
2529
|
});
|
|
2397
2530
|
}
|
|
2398
|
-
|
|
2531
|
+
fs12.writeFileSync(workspaceConfigPath, configContent);
|
|
2399
2532
|
if (config.addToGitignore) {
|
|
2400
2533
|
updateGitignore(workspacePath, config.storageMode, config.tools);
|
|
2401
2534
|
}
|
|
@@ -2435,8 +2568,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2435
2568
|
}
|
|
2436
2569
|
try {
|
|
2437
2570
|
let content = "";
|
|
2438
|
-
if (
|
|
2439
|
-
content =
|
|
2571
|
+
if (fs12.existsSync(gitignorePath)) {
|
|
2572
|
+
content = fs12.readFileSync(gitignorePath, "utf-8");
|
|
2440
2573
|
}
|
|
2441
2574
|
const lines = content.split("\n").map((line) => line.trim());
|
|
2442
2575
|
const newEntries = [];
|
|
@@ -2461,7 +2594,7 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2461
2594
|
newContent += "\n# rrce-workflow generated folders (uncomment to ignore)\n";
|
|
2462
2595
|
}
|
|
2463
2596
|
newContent += newEntries.map((e) => `# ${e}`).join("\n") + "\n";
|
|
2464
|
-
|
|
2597
|
+
fs12.writeFileSync(gitignorePath, newContent);
|
|
2465
2598
|
return true;
|
|
2466
2599
|
} catch {
|
|
2467
2600
|
return false;
|
|
@@ -2482,7 +2615,7 @@ var init_setup_flow = __esm({
|
|
|
2482
2615
|
// src/commands/wizard/link-flow.ts
|
|
2483
2616
|
import { multiselect as multiselect3, spinner as spinner3, note as note4, outro as outro3, cancel as cancel3, isCancel as isCancel4 } from "@clack/prompts";
|
|
2484
2617
|
import pc5 from "picocolors";
|
|
2485
|
-
import * as
|
|
2618
|
+
import * as fs13 from "fs";
|
|
2486
2619
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
2487
2620
|
const projects = scanForProjects({
|
|
2488
2621
|
excludeWorkspace: workspaceName,
|
|
@@ -2520,7 +2653,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
2520
2653
|
const s = spinner3();
|
|
2521
2654
|
s.start("Linking projects");
|
|
2522
2655
|
const configFilePath = getConfigPath(workspacePath);
|
|
2523
|
-
let configContent =
|
|
2656
|
+
let configContent = fs13.readFileSync(configFilePath, "utf-8");
|
|
2524
2657
|
if (configContent.includes("linked_projects:")) {
|
|
2525
2658
|
const lines = configContent.split("\n");
|
|
2526
2659
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -2547,7 +2680,7 @@ linked_projects:
|
|
|
2547
2680
|
`;
|
|
2548
2681
|
});
|
|
2549
2682
|
}
|
|
2550
|
-
|
|
2683
|
+
fs13.writeFileSync(configFilePath, configContent);
|
|
2551
2684
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
2552
2685
|
s.stop("Projects linked");
|
|
2553
2686
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
@@ -2572,7 +2705,7 @@ var init_link_flow = __esm({
|
|
|
2572
2705
|
// src/commands/wizard/sync-flow.ts
|
|
2573
2706
|
import { confirm as confirm3, spinner as spinner4, note as note5, outro as outro4, cancel as cancel4, isCancel as isCancel5 } from "@clack/prompts";
|
|
2574
2707
|
import pc6 from "picocolors";
|
|
2575
|
-
import * as
|
|
2708
|
+
import * as fs14 from "fs";
|
|
2576
2709
|
import * as path13 from "path";
|
|
2577
2710
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
2578
2711
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
@@ -2580,7 +2713,7 @@ async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
|
2580
2713
|
const globalPath = path13.join(customGlobalPath, "workspaces", workspaceName);
|
|
2581
2714
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
2582
2715
|
const existingDirs = subdirs.filter(
|
|
2583
|
-
(dir) =>
|
|
2716
|
+
(dir) => fs14.existsSync(path13.join(localPath, dir))
|
|
2584
2717
|
);
|
|
2585
2718
|
if (existingDirs.length === 0) {
|
|
2586
2719
|
outro4(pc6.yellow("No data found in workspace storage to sync."));
|
|
@@ -2639,7 +2772,7 @@ var init_sync_flow = __esm({
|
|
|
2639
2772
|
// src/commands/wizard/update-flow.ts
|
|
2640
2773
|
import { confirm as confirm4, spinner as spinner5, note as note6, outro as outro5, cancel as cancel5, isCancel as isCancel6 } from "@clack/prompts";
|
|
2641
2774
|
import pc7 from "picocolors";
|
|
2642
|
-
import * as
|
|
2775
|
+
import * as fs15 from "fs";
|
|
2643
2776
|
import * as path14 from "path";
|
|
2644
2777
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
2645
2778
|
const s = spinner5();
|
|
@@ -2673,7 +2806,7 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
2673
2806
|
copyDirToAllStoragePaths(path14.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
2674
2807
|
}
|
|
2675
2808
|
const configFilePath = getConfigPath(workspacePath);
|
|
2676
|
-
const configContent =
|
|
2809
|
+
const configContent = fs15.readFileSync(configFilePath, "utf-8");
|
|
2677
2810
|
if (configContent.includes("copilot: true")) {
|
|
2678
2811
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
2679
2812
|
ensureDir(copilotPath);
|
|
@@ -2728,7 +2861,7 @@ __export(wizard_exports, {
|
|
|
2728
2861
|
});
|
|
2729
2862
|
import { intro as intro2, select as select4, spinner as spinner6, note as note7, outro as outro6, isCancel as isCancel7 } from "@clack/prompts";
|
|
2730
2863
|
import pc8 from "picocolors";
|
|
2731
|
-
import * as
|
|
2864
|
+
import * as fs16 from "fs";
|
|
2732
2865
|
async function runWizard() {
|
|
2733
2866
|
intro2(pc8.cyan(pc8.inverse(" RRCE-Workflow Setup ")));
|
|
2734
2867
|
const s = spinner6();
|
|
@@ -2748,18 +2881,18 @@ Workspace: ${pc8.bold(workspaceName)}`,
|
|
|
2748
2881
|
workspacePath
|
|
2749
2882
|
});
|
|
2750
2883
|
const configFilePath = getConfigPath(workspacePath);
|
|
2751
|
-
const isAlreadyConfigured =
|
|
2884
|
+
const isAlreadyConfigured = fs16.existsSync(configFilePath);
|
|
2752
2885
|
let currentStorageMode = null;
|
|
2753
2886
|
if (isAlreadyConfigured) {
|
|
2754
2887
|
try {
|
|
2755
|
-
const configContent =
|
|
2888
|
+
const configContent = fs16.readFileSync(configFilePath, "utf-8");
|
|
2756
2889
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
2757
2890
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
2758
2891
|
} catch {
|
|
2759
2892
|
}
|
|
2760
2893
|
}
|
|
2761
2894
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
2762
|
-
const hasLocalData =
|
|
2895
|
+
const hasLocalData = fs16.existsSync(localDataPath);
|
|
2763
2896
|
if (isAlreadyConfigured) {
|
|
2764
2897
|
const menuOptions = [];
|
|
2765
2898
|
menuOptions.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rrce-workflow",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.30",
|
|
4
4
|
"description": "RRCE-Workflow TUI - Agentic code workflow generator for AI-assisted development",
|
|
5
5
|
"author": "RRCE Team",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,11 +50,17 @@
|
|
|
50
50
|
"@clack/prompts": "^0.11.0",
|
|
51
51
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
52
52
|
"gray-matter": "^4.0.3",
|
|
53
|
+
"ink": "^6.6.0",
|
|
54
|
+
"ink-link": "^5.0.0",
|
|
55
|
+
"ink-spinner": "^5.0.0",
|
|
56
|
+
"ink-text-input": "^6.0.0",
|
|
53
57
|
"picocolors": "^1.1.1",
|
|
58
|
+
"react": "^19.2.3",
|
|
54
59
|
"zod": "^4.2.1"
|
|
55
60
|
},
|
|
56
61
|
"devDependencies": {
|
|
57
62
|
"@types/node": "^25.0.3",
|
|
63
|
+
"@types/react": "^19.2.7",
|
|
58
64
|
"esbuild": "^0.27.2",
|
|
59
65
|
"tsx": "^4.21.0",
|
|
60
66
|
"typescript": "^5.9.3"
|