rrce-workflow 0.2.29 → 0.2.31
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 +302 -165
- 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) {
|
|
@@ -1160,7 +1175,7 @@ import {
|
|
|
1160
1175
|
ListPromptsRequestSchema,
|
|
1161
1176
|
GetPromptRequestSchema
|
|
1162
1177
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
1163
|
-
async function startMCPServer() {
|
|
1178
|
+
async function startMCPServer(options = {}) {
|
|
1164
1179
|
try {
|
|
1165
1180
|
logger.info("Starting MCP Server...");
|
|
1166
1181
|
process.on("uncaughtException", (error) => {
|
|
@@ -1182,8 +1197,12 @@ async function startMCPServer() {
|
|
|
1182
1197
|
registerResourceHandlers(mcpServer);
|
|
1183
1198
|
registerToolHandlers(mcpServer);
|
|
1184
1199
|
registerPromptHandlers(mcpServer);
|
|
1185
|
-
|
|
1186
|
-
|
|
1200
|
+
if (!options.interactive) {
|
|
1201
|
+
const transport = new StdioServerTransport();
|
|
1202
|
+
await mcpServer.connect(transport);
|
|
1203
|
+
} else {
|
|
1204
|
+
logger.info("Running in interactive mode (Stdio transport detached)");
|
|
1205
|
+
}
|
|
1187
1206
|
serverState = { running: true, port: config.server.port, pid: process.pid };
|
|
1188
1207
|
const exposed = getExposedProjects().map((p) => p.name).join(", ");
|
|
1189
1208
|
logger.info(`RRCE MCP Hub started (pid: ${process.pid})`, { exposedProjects: exposed });
|
|
@@ -1683,6 +1702,226 @@ var init_install = __esm({
|
|
|
1683
1702
|
}
|
|
1684
1703
|
});
|
|
1685
1704
|
|
|
1705
|
+
// src/mcp/ui/Header.tsx
|
|
1706
|
+
import "react";
|
|
1707
|
+
import { Box, Text } from "ink";
|
|
1708
|
+
import { jsx } from "react/jsx-runtime";
|
|
1709
|
+
var Header;
|
|
1710
|
+
var init_Header = __esm({
|
|
1711
|
+
"src/mcp/ui/Header.tsx"() {
|
|
1712
|
+
"use strict";
|
|
1713
|
+
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 " }) }) });
|
|
1714
|
+
}
|
|
1715
|
+
});
|
|
1716
|
+
|
|
1717
|
+
// src/mcp/ui/StatusBoard.tsx
|
|
1718
|
+
import "react";
|
|
1719
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
1720
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
1721
|
+
var StatusBoard;
|
|
1722
|
+
var init_StatusBoard = __esm({
|
|
1723
|
+
"src/mcp/ui/StatusBoard.tsx"() {
|
|
1724
|
+
"use strict";
|
|
1725
|
+
StatusBoard = ({ exposedLabel, port, pid }) => {
|
|
1726
|
+
return /* @__PURE__ */ jsx2(Box2, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs(Text2, { children: [
|
|
1727
|
+
"\u{1F4CB} ",
|
|
1728
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: exposedLabel }),
|
|
1729
|
+
" ",
|
|
1730
|
+
"\u2502",
|
|
1731
|
+
" Port: ",
|
|
1732
|
+
/* @__PURE__ */ jsx2(Text2, { color: "green", children: port }),
|
|
1733
|
+
" ",
|
|
1734
|
+
"\u2502",
|
|
1735
|
+
" PID: ",
|
|
1736
|
+
/* @__PURE__ */ jsx2(Text2, { color: "green", children: pid })
|
|
1737
|
+
] }) });
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
// src/mcp/ui/LogViewer.tsx
|
|
1743
|
+
import "react";
|
|
1744
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
1745
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1746
|
+
var LogViewer;
|
|
1747
|
+
var init_LogViewer = __esm({
|
|
1748
|
+
"src/mcp/ui/LogViewer.tsx"() {
|
|
1749
|
+
"use strict";
|
|
1750
|
+
LogViewer = ({ logs, height }) => {
|
|
1751
|
+
const visibleLogs = logs.slice(-height);
|
|
1752
|
+
const emptyLines = Math.max(0, height - visibleLogs.length);
|
|
1753
|
+
const padding = Array(emptyLines).fill("");
|
|
1754
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "dim", paddingX: 1, height: height + 2, flexGrow: 1, children: [
|
|
1755
|
+
padding.map((_, i) => /* @__PURE__ */ jsx3(Text3, { children: " " }, `empty-${i}`)),
|
|
1756
|
+
visibleLogs.map((log, i) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate-end", children: log }, `log-${i}`))
|
|
1757
|
+
] });
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
});
|
|
1761
|
+
|
|
1762
|
+
// src/mcp/ui/CommandBar.tsx
|
|
1763
|
+
import "react";
|
|
1764
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
1765
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1766
|
+
var CommandBar;
|
|
1767
|
+
var init_CommandBar = __esm({
|
|
1768
|
+
"src/mcp/ui/CommandBar.tsx"() {
|
|
1769
|
+
"use strict";
|
|
1770
|
+
CommandBar = () => {
|
|
1771
|
+
return /* @__PURE__ */ jsx4(Box4, { borderStyle: "single", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
1772
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "q" }),
|
|
1773
|
+
":Quit ",
|
|
1774
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "p" }),
|
|
1775
|
+
":Projects ",
|
|
1776
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "i" }),
|
|
1777
|
+
":Install ",
|
|
1778
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "r" }),
|
|
1779
|
+
":Reload ",
|
|
1780
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "c" }),
|
|
1781
|
+
":Clear ",
|
|
1782
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "?" }),
|
|
1783
|
+
":Help"
|
|
1784
|
+
] }) });
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
});
|
|
1788
|
+
|
|
1789
|
+
// src/mcp/ui/Dashboard.tsx
|
|
1790
|
+
import "react";
|
|
1791
|
+
import { Box as Box5 } from "ink";
|
|
1792
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1793
|
+
var Dashboard;
|
|
1794
|
+
var init_Dashboard = __esm({
|
|
1795
|
+
"src/mcp/ui/Dashboard.tsx"() {
|
|
1796
|
+
"use strict";
|
|
1797
|
+
init_Header();
|
|
1798
|
+
init_StatusBoard();
|
|
1799
|
+
init_LogViewer();
|
|
1800
|
+
init_CommandBar();
|
|
1801
|
+
Dashboard = ({ logs, exposedLabel, port, pid, logHeight }) => {
|
|
1802
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", padding: 0, children: [
|
|
1803
|
+
/* @__PURE__ */ jsx5(Header, {}),
|
|
1804
|
+
/* @__PURE__ */ jsx5(LogViewer, { logs, height: logHeight }),
|
|
1805
|
+
/* @__PURE__ */ jsx5(StatusBoard, { exposedLabel, port, pid }),
|
|
1806
|
+
/* @__PURE__ */ jsx5(CommandBar, {})
|
|
1807
|
+
] });
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
|
|
1812
|
+
// src/mcp/ui/App.tsx
|
|
1813
|
+
var App_exports = {};
|
|
1814
|
+
__export(App_exports, {
|
|
1815
|
+
App: () => App
|
|
1816
|
+
});
|
|
1817
|
+
import { useState, useEffect as useEffect2 } from "react";
|
|
1818
|
+
import { useInput, useApp } from "ink";
|
|
1819
|
+
import fs11 from "fs";
|
|
1820
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1821
|
+
var App;
|
|
1822
|
+
var init_App = __esm({
|
|
1823
|
+
"src/mcp/ui/App.tsx"() {
|
|
1824
|
+
"use strict";
|
|
1825
|
+
init_Dashboard();
|
|
1826
|
+
init_config();
|
|
1827
|
+
init_detection();
|
|
1828
|
+
init_logger();
|
|
1829
|
+
init_server();
|
|
1830
|
+
App = ({ onExit, onConfigure, onInstall, initialPort }) => {
|
|
1831
|
+
const { exit } = useApp();
|
|
1832
|
+
const [logs, setLogs] = useState([]);
|
|
1833
|
+
const [serverInfo, setServerInfo] = useState({
|
|
1834
|
+
port: initialPort,
|
|
1835
|
+
pid: process.pid,
|
|
1836
|
+
running: false
|
|
1837
|
+
});
|
|
1838
|
+
const config = loadMCPConfig();
|
|
1839
|
+
const projects = scanForProjects();
|
|
1840
|
+
const exposedProjects = projects.filter((p) => {
|
|
1841
|
+
const cfg = config.projects.find((c) => c.name === p.name);
|
|
1842
|
+
return cfg?.expose ?? config.defaults.includeNew;
|
|
1843
|
+
});
|
|
1844
|
+
const exposedNames = exposedProjects.map((p) => p.name).slice(0, 5);
|
|
1845
|
+
const exposedLabel = exposedNames.length > 0 ? exposedNames.join(", ") + (exposedProjects.length > 5 ? ` (+${exposedProjects.length - 5} more)` : "") : "(none)";
|
|
1846
|
+
useEffect2(() => {
|
|
1847
|
+
const start = async () => {
|
|
1848
|
+
const status = getMCPServerStatus();
|
|
1849
|
+
if (!status.running) {
|
|
1850
|
+
try {
|
|
1851
|
+
const res = await startMCPServer({ interactive: true });
|
|
1852
|
+
setServerInfo((prev) => ({ ...prev, running: true, port: res.port, pid: res.pid }));
|
|
1853
|
+
} catch (e) {
|
|
1854
|
+
setLogs((prev) => [...prev, `Error starting server: ${e}`]);
|
|
1855
|
+
}
|
|
1856
|
+
} else {
|
|
1857
|
+
setServerInfo((prev) => ({ ...prev, running: true, port: status.port || initialPort, pid: status.pid || process.pid }));
|
|
1858
|
+
}
|
|
1859
|
+
};
|
|
1860
|
+
start();
|
|
1861
|
+
return () => {
|
|
1862
|
+
};
|
|
1863
|
+
}, []);
|
|
1864
|
+
useEffect2(() => {
|
|
1865
|
+
const logPath = getLogFilePath();
|
|
1866
|
+
let lastSize = 0;
|
|
1867
|
+
if (fs11.existsSync(logPath)) {
|
|
1868
|
+
const stats = fs11.statSync(logPath);
|
|
1869
|
+
lastSize = stats.size;
|
|
1870
|
+
}
|
|
1871
|
+
const interval = setInterval(() => {
|
|
1872
|
+
if (fs11.existsSync(logPath)) {
|
|
1873
|
+
const stats = fs11.statSync(logPath);
|
|
1874
|
+
if (stats.size > lastSize) {
|
|
1875
|
+
const buffer = Buffer.alloc(stats.size - lastSize);
|
|
1876
|
+
const fd = fs11.openSync(logPath, "r");
|
|
1877
|
+
fs11.readSync(fd, buffer, 0, buffer.length, lastSize);
|
|
1878
|
+
fs11.closeSync(fd);
|
|
1879
|
+
const newContent = buffer.toString("utf-8");
|
|
1880
|
+
const newLines = newContent.split("\n").filter((l) => l.trim());
|
|
1881
|
+
setLogs((prev) => {
|
|
1882
|
+
const next = [...prev, ...newLines];
|
|
1883
|
+
return next.slice(-50);
|
|
1884
|
+
});
|
|
1885
|
+
lastSize = stats.size;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
}, 500);
|
|
1889
|
+
return () => clearInterval(interval);
|
|
1890
|
+
}, []);
|
|
1891
|
+
useInput((input, key) => {
|
|
1892
|
+
if (input === "q" || key.ctrl && input === "c") {
|
|
1893
|
+
stopMCPServer();
|
|
1894
|
+
onExit();
|
|
1895
|
+
}
|
|
1896
|
+
if (input === "p") {
|
|
1897
|
+
onConfigure();
|
|
1898
|
+
}
|
|
1899
|
+
if (input === "i") {
|
|
1900
|
+
onInstall();
|
|
1901
|
+
}
|
|
1902
|
+
if (input === "c") {
|
|
1903
|
+
setLogs([]);
|
|
1904
|
+
}
|
|
1905
|
+
if (input === "r") {
|
|
1906
|
+
setLogs((prev) => [...prev, "[INFO] Config reload requested..."]);
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1909
|
+
const termHeight = process.stdout.rows || 24;
|
|
1910
|
+
const logHeight = Math.max(5, termHeight - 12);
|
|
1911
|
+
return /* @__PURE__ */ jsx6(
|
|
1912
|
+
Dashboard,
|
|
1913
|
+
{
|
|
1914
|
+
logs,
|
|
1915
|
+
exposedLabel,
|
|
1916
|
+
port: serverInfo.port,
|
|
1917
|
+
pid: serverInfo.pid,
|
|
1918
|
+
logHeight
|
|
1919
|
+
}
|
|
1920
|
+
);
|
|
1921
|
+
};
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
|
|
1686
1925
|
// src/mcp/index.ts
|
|
1687
1926
|
var mcp_exports = {};
|
|
1688
1927
|
__export(mcp_exports, {
|
|
@@ -1694,9 +1933,13 @@ async function runMCP(subcommand2) {
|
|
|
1694
1933
|
if (subcommand2) {
|
|
1695
1934
|
switch (subcommand2) {
|
|
1696
1935
|
case "start":
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
}
|
|
1936
|
+
if (process.stdout.isTTY) {
|
|
1937
|
+
await handleStartServer();
|
|
1938
|
+
} else {
|
|
1939
|
+
await startMCPServer();
|
|
1940
|
+
await new Promise(() => {
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1700
1943
|
return;
|
|
1701
1944
|
case "stop":
|
|
1702
1945
|
await handleStopServer();
|
|
@@ -1848,9 +2091,11 @@ async function handleInstallWizard(workspacePath) {
|
|
|
1848
2091
|
}
|
|
1849
2092
|
}
|
|
1850
2093
|
async function handleStartServer() {
|
|
1851
|
-
const
|
|
1852
|
-
const {
|
|
1853
|
-
const
|
|
2094
|
+
const React7 = await import("react");
|
|
2095
|
+
const { render } = await import("ink");
|
|
2096
|
+
const { App: App2 } = await Promise.resolve().then(() => (init_App(), App_exports));
|
|
2097
|
+
const { loadMCPConfig: loadMCPConfig2, saveMCPConfig: saveMCPConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2098
|
+
const config = loadMCPConfig2();
|
|
1854
2099
|
const projects = scanForProjects();
|
|
1855
2100
|
const exposedProjects = projects.filter((p) => {
|
|
1856
2101
|
const cfg = config.projects.find((c) => c.name === p.name);
|
|
@@ -1867,7 +2112,7 @@ async function handleStartServer() {
|
|
|
1867
2112
|
}
|
|
1868
2113
|
}
|
|
1869
2114
|
const status = getMCPServerStatus();
|
|
1870
|
-
let
|
|
2115
|
+
let initialPort = config.server.port;
|
|
1871
2116
|
if (!status.running) {
|
|
1872
2117
|
const portInput = await text({
|
|
1873
2118
|
message: "Select port for MCP Server",
|
|
@@ -1878,153 +2123,45 @@ async function handleStartServer() {
|
|
|
1878
2123
|
}
|
|
1879
2124
|
});
|
|
1880
2125
|
if (isCancel2(portInput)) return;
|
|
1881
|
-
newPort = parseInt(portInput, 10);
|
|
2126
|
+
const newPort = parseInt(portInput, 10);
|
|
1882
2127
|
if (newPort !== config.server.port) {
|
|
1883
2128
|
config.server.port = newPort;
|
|
1884
|
-
|
|
2129
|
+
saveMCPConfig2(config);
|
|
2130
|
+
initialPort = newPort;
|
|
1885
2131
|
}
|
|
1886
|
-
} else {
|
|
1887
|
-
newPort = status.port || newPort;
|
|
1888
|
-
note2(`Server is already running on port ${newPort}`, "Info");
|
|
1889
2132
|
}
|
|
1890
2133
|
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);
|
|
2134
|
+
let keepRunning = true;
|
|
2135
|
+
while (keepRunning) {
|
|
2136
|
+
let nextAction = "exit";
|
|
2137
|
+
const app = render(React7.createElement(App2, {
|
|
2138
|
+
initialPort,
|
|
2139
|
+
onExit: () => {
|
|
2140
|
+
nextAction = "exit";
|
|
2141
|
+
},
|
|
2142
|
+
onConfigure: () => {
|
|
2143
|
+
nextAction = "configure";
|
|
2144
|
+
},
|
|
2145
|
+
onInstall: () => {
|
|
2146
|
+
nextAction = "install";
|
|
2147
|
+
}
|
|
2148
|
+
}));
|
|
2149
|
+
await app.waitUntilExit();
|
|
2150
|
+
if (nextAction === "exit") {
|
|
2151
|
+
keepRunning = false;
|
|
2152
|
+
} else if (nextAction === "configure") {
|
|
2153
|
+
console.clear();
|
|
2154
|
+
await handleConfigure();
|
|
2155
|
+
} else if (nextAction === "install") {
|
|
2156
|
+
console.clear();
|
|
2157
|
+
const workspacePath = detectWorkspaceRoot();
|
|
2158
|
+
await handleInstallWizard(workspacePath);
|
|
2020
2159
|
}
|
|
2021
|
-
console.error(pc3.red("\nFailed to start/monitor server:"));
|
|
2022
|
-
console.error(error);
|
|
2023
2160
|
}
|
|
2024
2161
|
}
|
|
2025
2162
|
async function handleConfigureGlobalPath() {
|
|
2026
2163
|
const { resolveGlobalPath: resolveGlobalPath2 } = await Promise.resolve().then(() => (init_tui_utils(), tui_utils_exports));
|
|
2027
|
-
const
|
|
2164
|
+
const fs17 = await import("fs");
|
|
2028
2165
|
const path16 = await import("path");
|
|
2029
2166
|
note2(
|
|
2030
2167
|
`MCP Hub requires a ${pc3.bold("global storage path")} to store its configuration
|
|
@@ -2039,8 +2176,8 @@ locally in each project. MCP needs a central location.`,
|
|
|
2039
2176
|
return false;
|
|
2040
2177
|
}
|
|
2041
2178
|
try {
|
|
2042
|
-
if (!
|
|
2043
|
-
|
|
2179
|
+
if (!fs17.existsSync(resolvedPath)) {
|
|
2180
|
+
fs17.mkdirSync(resolvedPath, { recursive: true });
|
|
2044
2181
|
}
|
|
2045
2182
|
const config = loadMCPConfig();
|
|
2046
2183
|
saveMCPConfig(config);
|
|
@@ -2220,7 +2357,7 @@ var init_mcp = __esm({
|
|
|
2220
2357
|
// src/commands/wizard/setup-flow.ts
|
|
2221
2358
|
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
2359
|
import pc4 from "picocolors";
|
|
2223
|
-
import * as
|
|
2360
|
+
import * as fs12 from "fs";
|
|
2224
2361
|
import * as path12 from "path";
|
|
2225
2362
|
async function runSetupFlow(workspacePath, workspaceName, existingProjects) {
|
|
2226
2363
|
const s = spinner2();
|
|
@@ -2395,7 +2532,7 @@ linked_projects:
|
|
|
2395
2532
|
`;
|
|
2396
2533
|
});
|
|
2397
2534
|
}
|
|
2398
|
-
|
|
2535
|
+
fs12.writeFileSync(workspaceConfigPath, configContent);
|
|
2399
2536
|
if (config.addToGitignore) {
|
|
2400
2537
|
updateGitignore(workspacePath, config.storageMode, config.tools);
|
|
2401
2538
|
}
|
|
@@ -2435,8 +2572,8 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2435
2572
|
}
|
|
2436
2573
|
try {
|
|
2437
2574
|
let content = "";
|
|
2438
|
-
if (
|
|
2439
|
-
content =
|
|
2575
|
+
if (fs12.existsSync(gitignorePath)) {
|
|
2576
|
+
content = fs12.readFileSync(gitignorePath, "utf-8");
|
|
2440
2577
|
}
|
|
2441
2578
|
const lines = content.split("\n").map((line) => line.trim());
|
|
2442
2579
|
const newEntries = [];
|
|
@@ -2461,7 +2598,7 @@ function updateGitignore(workspacePath, storageMode, tools) {
|
|
|
2461
2598
|
newContent += "\n# rrce-workflow generated folders (uncomment to ignore)\n";
|
|
2462
2599
|
}
|
|
2463
2600
|
newContent += newEntries.map((e) => `# ${e}`).join("\n") + "\n";
|
|
2464
|
-
|
|
2601
|
+
fs12.writeFileSync(gitignorePath, newContent);
|
|
2465
2602
|
return true;
|
|
2466
2603
|
} catch {
|
|
2467
2604
|
return false;
|
|
@@ -2482,7 +2619,7 @@ var init_setup_flow = __esm({
|
|
|
2482
2619
|
// src/commands/wizard/link-flow.ts
|
|
2483
2620
|
import { multiselect as multiselect3, spinner as spinner3, note as note4, outro as outro3, cancel as cancel3, isCancel as isCancel4 } from "@clack/prompts";
|
|
2484
2621
|
import pc5 from "picocolors";
|
|
2485
|
-
import * as
|
|
2622
|
+
import * as fs13 from "fs";
|
|
2486
2623
|
async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
2487
2624
|
const projects = scanForProjects({
|
|
2488
2625
|
excludeWorkspace: workspaceName,
|
|
@@ -2520,7 +2657,7 @@ async function runLinkProjectsFlow(workspacePath, workspaceName) {
|
|
|
2520
2657
|
const s = spinner3();
|
|
2521
2658
|
s.start("Linking projects");
|
|
2522
2659
|
const configFilePath = getConfigPath(workspacePath);
|
|
2523
|
-
let configContent =
|
|
2660
|
+
let configContent = fs13.readFileSync(configFilePath, "utf-8");
|
|
2524
2661
|
if (configContent.includes("linked_projects:")) {
|
|
2525
2662
|
const lines = configContent.split("\n");
|
|
2526
2663
|
const linkedIndex = lines.findIndex((l) => l.trim() === "linked_projects:");
|
|
@@ -2547,7 +2684,7 @@ linked_projects:
|
|
|
2547
2684
|
`;
|
|
2548
2685
|
});
|
|
2549
2686
|
}
|
|
2550
|
-
|
|
2687
|
+
fs13.writeFileSync(configFilePath, configContent);
|
|
2551
2688
|
generateVSCodeWorkspace(workspacePath, workspaceName, selectedProjects, customGlobalPath);
|
|
2552
2689
|
s.stop("Projects linked");
|
|
2553
2690
|
const workspaceFile = `${workspaceName}.code-workspace`;
|
|
@@ -2572,7 +2709,7 @@ var init_link_flow = __esm({
|
|
|
2572
2709
|
// src/commands/wizard/sync-flow.ts
|
|
2573
2710
|
import { confirm as confirm3, spinner as spinner4, note as note5, outro as outro4, cancel as cancel4, isCancel as isCancel5 } from "@clack/prompts";
|
|
2574
2711
|
import pc6 from "picocolors";
|
|
2575
|
-
import * as
|
|
2712
|
+
import * as fs14 from "fs";
|
|
2576
2713
|
import * as path13 from "path";
|
|
2577
2714
|
async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
2578
2715
|
const localPath = getLocalWorkspacePath(workspacePath);
|
|
@@ -2580,7 +2717,7 @@ async function runSyncToGlobalFlow(workspacePath, workspaceName) {
|
|
|
2580
2717
|
const globalPath = path13.join(customGlobalPath, "workspaces", workspaceName);
|
|
2581
2718
|
const subdirs = ["knowledge", "prompts", "templates", "tasks", "refs"];
|
|
2582
2719
|
const existingDirs = subdirs.filter(
|
|
2583
|
-
(dir) =>
|
|
2720
|
+
(dir) => fs14.existsSync(path13.join(localPath, dir))
|
|
2584
2721
|
);
|
|
2585
2722
|
if (existingDirs.length === 0) {
|
|
2586
2723
|
outro4(pc6.yellow("No data found in workspace storage to sync."));
|
|
@@ -2639,7 +2776,7 @@ var init_sync_flow = __esm({
|
|
|
2639
2776
|
// src/commands/wizard/update-flow.ts
|
|
2640
2777
|
import { confirm as confirm4, spinner as spinner5, note as note6, outro as outro5, cancel as cancel5, isCancel as isCancel6 } from "@clack/prompts";
|
|
2641
2778
|
import pc7 from "picocolors";
|
|
2642
|
-
import * as
|
|
2779
|
+
import * as fs15 from "fs";
|
|
2643
2780
|
import * as path14 from "path";
|
|
2644
2781
|
async function runUpdateFlow(workspacePath, workspaceName, currentStorageMode) {
|
|
2645
2782
|
const s = spinner5();
|
|
@@ -2673,7 +2810,7 @@ ${dataPaths.map((p) => ` \u2022 ${p}`).join("\n")}`,
|
|
|
2673
2810
|
copyDirToAllStoragePaths(path14.join(agentCoreDir, "templates"), "templates", [dataPath]);
|
|
2674
2811
|
}
|
|
2675
2812
|
const configFilePath = getConfigPath(workspacePath);
|
|
2676
|
-
const configContent =
|
|
2813
|
+
const configContent = fs15.readFileSync(configFilePath, "utf-8");
|
|
2677
2814
|
if (configContent.includes("copilot: true")) {
|
|
2678
2815
|
const copilotPath = getAgentPromptPath(workspacePath, "copilot");
|
|
2679
2816
|
ensureDir(copilotPath);
|
|
@@ -2728,7 +2865,7 @@ __export(wizard_exports, {
|
|
|
2728
2865
|
});
|
|
2729
2866
|
import { intro as intro2, select as select4, spinner as spinner6, note as note7, outro as outro6, isCancel as isCancel7 } from "@clack/prompts";
|
|
2730
2867
|
import pc8 from "picocolors";
|
|
2731
|
-
import * as
|
|
2868
|
+
import * as fs16 from "fs";
|
|
2732
2869
|
async function runWizard() {
|
|
2733
2870
|
intro2(pc8.cyan(pc8.inverse(" RRCE-Workflow Setup ")));
|
|
2734
2871
|
const s = spinner6();
|
|
@@ -2748,18 +2885,18 @@ Workspace: ${pc8.bold(workspaceName)}`,
|
|
|
2748
2885
|
workspacePath
|
|
2749
2886
|
});
|
|
2750
2887
|
const configFilePath = getConfigPath(workspacePath);
|
|
2751
|
-
const isAlreadyConfigured =
|
|
2888
|
+
const isAlreadyConfigured = fs16.existsSync(configFilePath);
|
|
2752
2889
|
let currentStorageMode = null;
|
|
2753
2890
|
if (isAlreadyConfigured) {
|
|
2754
2891
|
try {
|
|
2755
|
-
const configContent =
|
|
2892
|
+
const configContent = fs16.readFileSync(configFilePath, "utf-8");
|
|
2756
2893
|
const modeMatch = configContent.match(/mode:\s*(global|workspace)/);
|
|
2757
2894
|
currentStorageMode = modeMatch?.[1] ?? null;
|
|
2758
2895
|
} catch {
|
|
2759
2896
|
}
|
|
2760
2897
|
}
|
|
2761
2898
|
const localDataPath = getLocalWorkspacePath(workspacePath);
|
|
2762
|
-
const hasLocalData =
|
|
2899
|
+
const hasLocalData = fs16.existsSync(localDataPath);
|
|
2763
2900
|
if (isAlreadyConfigured) {
|
|
2764
2901
|
const menuOptions = [];
|
|
2765
2902
|
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.31",
|
|
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"
|