rax-flow 0.1.5 → 0.1.7

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.
Files changed (223) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bin.js +27 -3
  3. package/dist/bin.js.map +1 -1
  4. package/dist/hub/__tests__/commands.test.d.ts.map +1 -0
  5. package/dist/hub/__tests__/commands.test.js +72 -0
  6. package/dist/hub/__tests__/commands.test.js.map +1 -0
  7. package/dist/hub/__tests__/history.test.d.ts.map +1 -0
  8. package/dist/hub/__tests__/history.test.js +119 -0
  9. package/dist/hub/__tests__/history.test.js.map +1 -0
  10. package/dist/hub/__tests__/parser.test.d.ts.map +1 -0
  11. package/dist/hub/__tests__/parser.test.js +92 -0
  12. package/dist/hub/__tests__/parser.test.js.map +1 -0
  13. package/dist/hub/chat/ChatApp.d.ts +2 -0
  14. package/dist/hub/chat/ChatApp.d.ts.map +1 -0
  15. package/dist/hub/chat/ChatApp.js +146 -0
  16. package/dist/hub/chat/ChatApp.js.map +1 -0
  17. package/dist/hub/chat/components/ChatInput.d.ts +9 -0
  18. package/dist/hub/chat/components/ChatInput.d.ts.map +1 -0
  19. package/dist/hub/chat/components/ChatInput.js +19 -0
  20. package/dist/hub/chat/components/ChatInput.js.map +1 -0
  21. package/dist/hub/chat/components/MessageList.d.ts +7 -0
  22. package/dist/hub/chat/components/MessageList.d.ts.map +1 -0
  23. package/dist/hub/chat/components/MessageList.js +6 -0
  24. package/dist/hub/chat/components/MessageList.js.map +1 -0
  25. package/dist/hub/chat/context.d.ts.map +1 -0
  26. package/dist/hub/chat/context.js +42 -0
  27. package/dist/hub/chat/context.js.map +1 -0
  28. package/dist/hub/chat/hooks/useChatHistory.d.ts +7 -0
  29. package/dist/hub/chat/hooks/useChatHistory.d.ts.map +1 -0
  30. package/dist/hub/chat/hooks/useChatHistory.js +31 -0
  31. package/dist/hub/chat/hooks/useChatHistory.js.map +1 -0
  32. package/dist/hub/chat/index.d.ts.map +1 -0
  33. package/dist/hub/chat/index.js +7 -0
  34. package/dist/hub/chat/index.js.map +1 -0
  35. package/dist/hub/chat/intent-parser.d.ts.map +1 -0
  36. package/dist/hub/chat/intent-parser.js +48 -0
  37. package/dist/hub/chat/intent-parser.js.map +1 -0
  38. package/dist/hub/chat/types.d.ts.map +1 -0
  39. package/dist/hub/chat/types.js +2 -0
  40. package/dist/hub/chat/types.js.map +1 -0
  41. package/dist/hub/commands/agents.d.ts.map +1 -0
  42. package/dist/hub/commands/agents.js +36 -0
  43. package/dist/hub/commands/agents.js.map +1 -0
  44. package/dist/hub/commands/index.d.ts.map +1 -0
  45. package/dist/hub/commands/index.js +120 -0
  46. package/dist/hub/commands/index.js.map +1 -0
  47. package/dist/hub/commands/logs.d.ts.map +1 -0
  48. package/dist/hub/commands/logs.js +53 -0
  49. package/dist/hub/commands/logs.js.map +1 -0
  50. package/dist/hub/commands/memory.d.ts.map +1 -0
  51. package/dist/hub/commands/memory.js +40 -0
  52. package/dist/hub/commands/memory.js.map +1 -0
  53. package/dist/hub/commands/metrics.d.ts.map +1 -0
  54. package/dist/hub/commands/metrics.js +35 -0
  55. package/dist/hub/commands/metrics.js.map +1 -0
  56. package/dist/hub/commands/providers.d.ts.map +1 -0
  57. package/dist/hub/commands/providers.js +26 -0
  58. package/dist/hub/commands/providers.js.map +1 -0
  59. package/dist/hub/commands/run.d.ts.map +1 -0
  60. package/dist/hub/commands/run.js +31 -0
  61. package/dist/hub/commands/run.js.map +1 -0
  62. package/dist/hub/commands/status.d.ts.map +1 -0
  63. package/dist/hub/commands/status.js +61 -0
  64. package/dist/hub/commands/status.js.map +1 -0
  65. package/dist/hub/commands/workflows.d.ts.map +1 -0
  66. package/dist/hub/commands/workflows.js +45 -0
  67. package/dist/hub/commands/workflows.js.map +1 -0
  68. package/dist/hub/config-loader.d.ts.map +1 -0
  69. package/dist/hub/config-loader.js +27 -0
  70. package/dist/hub/config-loader.js.map +1 -0
  71. package/dist/hub/event-listener.d.ts.map +1 -0
  72. package/dist/hub/event-listener.js +8 -0
  73. package/dist/hub/event-listener.js.map +1 -0
  74. package/dist/hub/history.d.ts.map +1 -0
  75. package/dist/hub/history.js +59 -0
  76. package/dist/hub/history.js.map +1 -0
  77. package/dist/hub/index.d.ts.map +1 -0
  78. package/dist/hub/index.js +102 -0
  79. package/dist/hub/index.js.map +1 -0
  80. package/dist/hub/parser.d.ts.map +1 -0
  81. package/dist/hub/parser.js +98 -0
  82. package/dist/hub/parser.js.map +1 -0
  83. package/dist/hub/styles/borders.d.ts.map +1 -0
  84. package/dist/hub/styles/borders.js +64 -0
  85. package/dist/hub/styles/borders.js.map +1 -0
  86. package/dist/hub/styles/colors.d.ts.map +1 -0
  87. package/dist/hub/styles/colors.js +115 -0
  88. package/dist/hub/styles/colors.js.map +1 -0
  89. package/dist/hub/styles/typography.d.ts.map +1 -0
  90. package/dist/hub/styles/typography.js +60 -0
  91. package/dist/hub/styles/typography.js.map +1 -0
  92. package/dist/hub/tui/App.d.ts +2 -0
  93. package/dist/hub/tui/App.d.ts.map +1 -0
  94. package/dist/hub/tui/App.js +53 -0
  95. package/dist/hub/tui/App.js.map +1 -0
  96. package/dist/hub/tui/components/AgentQueue.d.ts +6 -0
  97. package/dist/hub/tui/components/AgentQueue.d.ts.map +1 -0
  98. package/dist/hub/tui/components/AgentQueue.js +20 -0
  99. package/dist/hub/tui/components/AgentQueue.js.map +1 -0
  100. package/dist/hub/tui/components/DAGPanel.d.ts +16 -0
  101. package/dist/hub/tui/components/DAGPanel.d.ts.map +1 -0
  102. package/dist/hub/tui/components/DAGPanel.js +51 -0
  103. package/dist/hub/tui/components/DAGPanel.js.map +1 -0
  104. package/dist/hub/tui/components/Header.d.ts +7 -0
  105. package/dist/hub/tui/components/Header.d.ts.map +1 -0
  106. package/dist/hub/tui/components/Header.js +17 -0
  107. package/dist/hub/tui/components/Header.js.map +1 -0
  108. package/dist/hub/tui/components/LogsPanel.d.ts +6 -0
  109. package/dist/hub/tui/components/LogsPanel.d.ts.map +1 -0
  110. package/dist/hub/tui/components/LogsPanel.js +26 -0
  111. package/dist/hub/tui/components/LogsPanel.js.map +1 -0
  112. package/dist/hub/tui/components/StatusBar.d.ts +8 -0
  113. package/dist/hub/tui/components/StatusBar.d.ts.map +1 -0
  114. package/dist/hub/tui/components/StatusBar.js +7 -0
  115. package/dist/hub/tui/components/StatusBar.js.map +1 -0
  116. package/dist/hub/tui/hooks/useEvents.d.ts +2 -0
  117. package/dist/hub/tui/hooks/useEvents.d.ts.map +1 -0
  118. package/dist/hub/tui/hooks/useEvents.js +13 -0
  119. package/dist/hub/tui/hooks/useEvents.js.map +1 -0
  120. package/dist/hub/tui/index.d.ts.map +1 -0
  121. package/dist/hub/tui/index.js +7 -0
  122. package/dist/hub/tui/index.js.map +1 -0
  123. package/dist/hub/tui/types.d.ts.map +1 -0
  124. package/dist/hub/tui/types.js +2 -0
  125. package/dist/hub/tui/types.js.map +1 -0
  126. package/dist/hub/types.d.ts.map +1 -0
  127. package/dist/hub/types.js +2 -0
  128. package/dist/hub/types.js.map +1 -0
  129. package/dist/tui/App.d.ts +2 -0
  130. package/dist/tui/App.d.ts.map +1 -0
  131. package/dist/tui/App.js +31 -0
  132. package/dist/tui/App.js.map +1 -0
  133. package/dist/tui/components/ChatPanel.d.ts +14 -0
  134. package/dist/tui/components/ChatPanel.d.ts.map +1 -0
  135. package/dist/tui/components/ChatPanel.js +30 -0
  136. package/dist/tui/components/ChatPanel.js.map +1 -0
  137. package/dist/tui/components/Header.d.ts +9 -0
  138. package/dist/tui/components/Header.d.ts.map +1 -0
  139. package/dist/tui/components/Header.js +17 -0
  140. package/dist/tui/components/Header.js.map +1 -0
  141. package/dist/tui/components/InputBar.d.ts +8 -0
  142. package/dist/tui/components/InputBar.d.ts.map +1 -0
  143. package/dist/tui/components/InputBar.js +16 -0
  144. package/dist/tui/components/InputBar.js.map +1 -0
  145. package/dist/tui/components/StatusPanel.d.ts +20 -0
  146. package/dist/tui/components/StatusPanel.d.ts.map +1 -0
  147. package/dist/tui/components/StatusPanel.js +20 -0
  148. package/dist/tui/components/StatusPanel.js.map +1 -0
  149. package/dist/tui/hooks/useAppState.d.ts +38 -0
  150. package/dist/tui/hooks/useAppState.d.ts.map +1 -0
  151. package/dist/tui/hooks/useAppState.js +127 -0
  152. package/dist/tui/hooks/useAppState.js.map +1 -0
  153. package/dist/tui/index.d.ts +3 -0
  154. package/dist/tui/index.d.ts.map +1 -0
  155. package/dist/tui/index.js +8 -0
  156. package/dist/tui/index.js.map +1 -0
  157. package/package.json +17 -11
  158. package/src/bin.ts +29 -3
  159. package/src/hub/__tests__/commands.test.ts +84 -0
  160. package/src/hub/__tests__/history.test.ts +137 -0
  161. package/src/hub/__tests__/parser.test.ts +105 -0
  162. package/src/hub/commands/agents.ts +53 -0
  163. package/src/hub/commands/index.ts +137 -0
  164. package/src/hub/commands/logs.ts +70 -0
  165. package/src/hub/commands/memory.ts +47 -0
  166. package/src/hub/commands/metrics.ts +49 -0
  167. package/src/hub/commands/providers.ts +39 -0
  168. package/src/hub/commands/run.ts +37 -0
  169. package/src/hub/commands/status.ts +69 -0
  170. package/src/hub/commands/workflows.ts +64 -0
  171. package/src/hub/config-loader.ts +37 -0
  172. package/src/hub/event-listener.ts +13 -0
  173. package/src/hub/history.ts +66 -0
  174. package/src/hub/index.ts +120 -0
  175. package/src/hub/parser.ts +107 -0
  176. package/src/hub/styles/borders.ts +74 -0
  177. package/src/hub/styles/colors.ts +129 -0
  178. package/src/hub/styles/typography.ts +68 -0
  179. package/src/hub/types.ts +31 -0
  180. package/src/tui/App.tsx +61 -0
  181. package/src/tui/components/ChatPanel.tsx +79 -0
  182. package/src/tui/components/Header.tsx +53 -0
  183. package/src/tui/components/InputBar.tsx +55 -0
  184. package/src/tui/components/StatusPanel.tsx +85 -0
  185. package/src/tui/hooks/useAppState.ts +168 -0
  186. package/src/tui/index.ts +9 -0
  187. package/tsconfig.json +19 -3
  188. package/tsconfig.tsbuildinfo +1 -0
  189. package/dist/benchmark.d.ts +0 -10
  190. package/dist/bin.d.ts +0 -3
  191. package/dist/bootstrap.d.ts +0 -8
  192. package/dist/bridge-adapter-templates.d.ts +0 -4
  193. package/dist/bridge-test.d.ts +0 -7
  194. package/dist/dashboard.d.ts +0 -4
  195. package/dist/doctor.d.ts +0 -6
  196. package/dist/evolve.d.ts +0 -7
  197. package/dist/host-init-templates.d.ts +0 -16
  198. package/dist/index.d.ts +0 -11
  199. package/dist/init-host.d.ts +0 -10
  200. package/dist/install.d.ts +0 -8
  201. package/dist/run.d.ts +0 -16
  202. package/dist/styles.d.ts +0 -12
  203. package/dist/vendor-manifests.d.ts +0 -22
  204. package/package/dashboard/index.html +0 -420
  205. package/package/package.json +0 -28
  206. package/package/src/benchmark.ts +0 -156
  207. package/package/src/bin.ts +0 -127
  208. package/package/src/bootstrap.ts +0 -36
  209. package/package/src/bridge-adapter-templates.ts +0 -181
  210. package/package/src/bridge-test.ts +0 -107
  211. package/package/src/dashboard.ts +0 -51
  212. package/package/src/doctor.ts +0 -92
  213. package/package/src/evolve.ts +0 -74
  214. package/package/src/host-init-templates.ts +0 -134
  215. package/package/src/index.ts +0 -10
  216. package/package/src/init-host.ts +0 -285
  217. package/package/src/install.ts +0 -118
  218. package/package/src/run.ts +0 -317
  219. package/package/src/styles.ts +0 -12
  220. package/package/src/vendor-manifests.ts +0 -113
  221. package/package/src/ws-relay.ts +0 -156
  222. package/package/tsconfig.json +0 -12
  223. package/rax-flow-0.1.1.tgz +0 -0
@@ -0,0 +1,69 @@
1
+ import { HubContext } from "../types.js";
2
+ import { drawBox } from "../styles/borders.js";
3
+ import { colorize, formatStatus, statusIndicators } from "../styles/colors.js";
4
+ import { padRight } from "../styles/typography.js";
5
+
6
+ export async function showStatus(_args: string[], _flags: Record<string, string | boolean>, context: HubContext): Promise<void> {
7
+ const width = 61;
8
+
9
+ // Simulated status data (will be replaced with real data from orchestrator)
10
+ const status = {
11
+ orchestrator: "ACTIVE",
12
+ mode: "HOST-NATIVE",
13
+ activeAgents: "3/12",
14
+ currentRun: "L2: CodeGen [H] 67%",
15
+ fitness: "0.87",
16
+ fitnessTrend: "improving",
17
+ cacheHit: "94%",
18
+ memoryNodes: "247",
19
+ latency: "12ms",
20
+ providers: [
21
+ { name: "Host-Native", status: "online", latency: "12ms" },
22
+ { name: "Claude", status: "online", latency: "8ms" },
23
+ { name: "OpenAI", status: "idle", latency: "--" },
24
+ ],
25
+ activeWorkflows: [
26
+ { agent: "CodeGenerator", provider: "[H]", status: "running", progress: 67 },
27
+ { agent: "TestAgent", provider: "[H]", status: "queued", progress: 0 },
28
+ ],
29
+ };
30
+
31
+ const lines: string[] = [];
32
+
33
+ // Orchestrator status
34
+ lines.push(` Orchestrator: ${formatStatus("online")} ${colorize(status.orchestrator, "green")}`);
35
+ lines.push(` Mode: ${colorize(status.mode, "cyan")}`);
36
+ lines.push(` Active Agents: ${colorize(status.activeAgents, "yellow")}`);
37
+ lines.push("");
38
+
39
+ // Current run
40
+ if (status.currentRun) {
41
+ lines.push(` Current Run: ${statusIndicators.running} ${colorize(status.currentRun, "yellow")}`);
42
+ lines.push(` Fitness: ${colorize(status.fitness, "green")} (${colorize(status.fitnessTrend, "cyan")})`);
43
+ lines.push(` Cache Hit: ${colorize(status.cacheHit, "green")}`);
44
+ lines.push(` Memory Nodes: ${colorize(status.memoryNodes, "cyan")}`);
45
+ lines.push(` Latency: ${colorize(status.latency, "green")}`);
46
+ lines.push("");
47
+ }
48
+
49
+ // Active workflows
50
+ if (status.activeWorkflows.length > 0) {
51
+ lines.push(colorize(" Active Workflows:", "bright"));
52
+ for (const wf of status.activeWorkflows) {
53
+ const indicator = statusIndicators[wf.status as keyof typeof statusIndicators] || "○";
54
+ const color = wf.status === "running" ? "yellow" : wf.status === "queued" ? "gray" : "white";
55
+ lines.push(` ${indicator} ${padRight(wf.agent, 20)} ${wf.provider} ${colorize(wf.status.toUpperCase(), color)}`);
56
+ }
57
+ lines.push("");
58
+ }
59
+
60
+ // Providers
61
+ lines.push(colorize(" Providers:", "bright"));
62
+ for (const provider of status.providers) {
63
+ const indicator = formatStatus(provider.status);
64
+ const latencyStr = provider.latency !== "--" ? `${provider.latency}` : "--";
65
+ lines.push(` ${indicator} ${padRight(provider.name, 18)} ${colorize(latencyStr, "gray")}`);
66
+ }
67
+
68
+ console.log(drawBox(lines, width, "SYSTEM STATUS"));
69
+ }
@@ -0,0 +1,64 @@
1
+ import { HubContext } from "../types.js";
2
+ import { drawBox } from "../styles/borders.js";
3
+ import { colorize } from "../styles/colors.js";
4
+ import * as fs from "fs/promises";
5
+ import * as path from "path";
6
+
7
+ interface WorkflowInfo {
8
+ name: string;
9
+ description: string;
10
+ fitness?: number;
11
+ recommended?: boolean;
12
+ }
13
+
14
+ export async function listWorkflows(_args: string[], _flags: Record<string, string | boolean>, context: HubContext): Promise<void> {
15
+ const width = 70;
16
+ const lines: string[] = [];
17
+
18
+ // Try to find workflow files
19
+ const workflowDir = path.join(context.config.project || process.cwd(), ".rax", "workflows");
20
+ const workflows: WorkflowInfo[] = [];
21
+
22
+ try {
23
+ const files = await fs.readdir(workflowDir);
24
+ for (const file of files.filter(f => f.endsWith('.json'))) {
25
+ const filePath = path.join(workflowDir, file);
26
+ const content = await fs.readFile(filePath, 'utf-8');
27
+ const workflow = JSON.parse(content);
28
+ workflows.push({
29
+ name: file.replace('.json', ''),
30
+ description: workflow.description || 'No description',
31
+ fitness: workflow.fitness,
32
+ recommended: workflow.recommended,
33
+ });
34
+ }
35
+ } catch {
36
+ // Directory doesn't exist or is empty, use defaults
37
+ }
38
+
39
+ // Add default workflows
40
+ if (workflows.length === 0) {
41
+ workflows.push(
42
+ { name: "default-routing", description: "Standard workflow with intent classification", fitness: 0.87 },
43
+ { name: "secure-api-blueprint", description: "Security-focused API generation", fitness: 0.92 },
44
+ { name: "test-heavy-workflow", description: "Prioritizes test generation", fitness: 0.89 },
45
+ { name: "mutation-evolved-v3", description: "Optimized with mutations", fitness: 0.96, recommended: true }
46
+ );
47
+ }
48
+
49
+ lines.push(` ${colorize("WORKFLOW", "bright")} ${colorize("DESCRIPTION", "bright")} ${colorize("FITNESS", "bright")}`);
50
+ lines.push(" " + "─".repeat(66));
51
+
52
+ for (const wf of workflows) {
53
+ const name = wf.name.slice(0, 22).padEnd(24);
54
+ const desc = wf.description.slice(0, 25).padEnd(27);
55
+ const fitness = wf.fitness ? colorize(wf.fitness.toFixed(2), wf.fitness >= 0.9 ? "green" : "yellow") : "--";
56
+ const marker = wf.recommended ? colorize(" ★", "yellow") : "";
57
+ lines.push(` • ${name} ${desc} ${fitness}${marker}`);
58
+ }
59
+
60
+ lines.push("");
61
+ lines.push(` ${colorize("Usage:", "bright")} run -w <workflow-name> "<prompt>"`);
62
+
63
+ console.log(drawBox(lines, width, "WORKFLOWS"));
64
+ }
@@ -0,0 +1,37 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { HubConfig } from "./types.js";
4
+
5
+ interface RaxRcConfig {
6
+ project?: string;
7
+ providers?: string[];
8
+ theme?: 'industrial' | 'minimal' | 'high-contrast';
9
+ [key: string]: unknown;
10
+ }
11
+
12
+ export async function loadConfig(cwd: string): Promise<HubConfig> {
13
+ const configPath = path.join(cwd, ".raxrc");
14
+
15
+ try {
16
+ const content = await fs.readFile(configPath, "utf-8");
17
+ const config: RaxRcConfig = JSON.parse(content);
18
+
19
+ return {
20
+ project: config.project,
21
+ providers: config.providers,
22
+ theme: config.theme || 'industrial',
23
+ };
24
+ } catch {
25
+ // Return default config if .raxrc doesn't exist or is invalid
26
+ return {
27
+ project: path.basename(cwd),
28
+ providers: [],
29
+ theme: 'industrial',
30
+ };
31
+ }
32
+ }
33
+
34
+ export async function saveConfig(cwd: string, config: HubConfig): Promise<void> {
35
+ const configPath = path.join(cwd, ".raxrc");
36
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2));
37
+ }
@@ -0,0 +1,13 @@
1
+ export interface RuntimeEvent {
2
+ type: string;
3
+ timestamp: number;
4
+ payload: unknown;
5
+ }
6
+
7
+ export function subscribeToEvents(_callback: (event: RuntimeEvent) => void): () => void {
8
+ // TODO: Integrate with RuntimeEventBus from core
9
+ // For now, return a no-op unsubscribe
10
+ return () => {
11
+ // Cleanup
12
+ };
13
+ }
@@ -0,0 +1,66 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+
4
+ export class CommandHistory {
5
+ private history: string[] = [];
6
+ private position = -1;
7
+ private readonly historyPath: string;
8
+
9
+ constructor(cwd: string) {
10
+ this.historyPath = path.join(cwd, ".rax", "history.json");
11
+ }
12
+
13
+ add(command: string): void {
14
+ // Avoid duplicates at the end
15
+ if (this.history.length === 0 || this.history[this.history.length - 1] !== command) {
16
+ this.history.push(command);
17
+ }
18
+ this.position = this.history.length;
19
+ }
20
+
21
+ up(): string | undefined {
22
+ if (this.position > 0) {
23
+ this.position--;
24
+ return this.history[this.position];
25
+ }
26
+ return undefined;
27
+ }
28
+
29
+ down(): string | undefined {
30
+ if (this.position < this.history.length - 1) {
31
+ this.position++;
32
+ return this.history[this.position];
33
+ }
34
+ this.position = this.history.length;
35
+ return undefined;
36
+ }
37
+
38
+ async save(): Promise<void> {
39
+ try {
40
+ const dir = path.dirname(this.historyPath);
41
+ await fs.mkdir(dir, { recursive: true });
42
+ await fs.writeFile(
43
+ this.historyPath,
44
+ JSON.stringify(this.history.slice(-1000), null, 2) // Keep last 1000 commands
45
+ );
46
+ } catch {
47
+ // Silently fail if we can't save history
48
+ }
49
+ }
50
+
51
+ async load(): Promise<void> {
52
+ try {
53
+ const data = await fs.readFile(this.historyPath, "utf-8");
54
+ this.history = JSON.parse(data);
55
+ this.position = this.history.length;
56
+ } catch {
57
+ // No history file yet, start fresh
58
+ this.history = [];
59
+ this.position = 0;
60
+ }
61
+ }
62
+
63
+ getAll(): string[] {
64
+ return [...this.history];
65
+ }
66
+ }
@@ -0,0 +1,120 @@
1
+ import * as readline from "readline";
2
+ import { HubOptions, HubContext, Command } from "./types.js";
3
+ import { parseCommand, getCompletions } from "./parser.js";
4
+ import { CommandHistory } from "./history.js";
5
+ import { subscribeToEvents } from "./event-listener.js";
6
+ import { getCommandRegistry } from "./commands/index.js";
7
+ import { loadConfig } from "./config-loader.js";
8
+
9
+ const WELCOME_MESSAGE = `
10
+ ┌─────────────────────────────────────────────────────────────┐
11
+ │ ■ RAX-FLOW HUB [HOST-NATIVE] ● READY │
12
+ │ Project: %PROJECT% Agents: 12/12 Online │
13
+ ├─────────────────────────────────────────────────────────────┤
14
+ │ // BIENVENUE — Tapez 'help' ou '?' pour commencer │
15
+ └─────────────────────────────────────────────────────────────┘
16
+ `;
17
+
18
+ export async function startHub(options: HubOptions): Promise<void> {
19
+ const config = options.config || (await loadConfig(options.cwd));
20
+ const context: HubContext = {
21
+ config,
22
+ };
23
+
24
+ const history = new CommandHistory(options.cwd);
25
+ await history.load();
26
+
27
+ const commands = getCommandRegistry();
28
+
29
+ console.log(WELCOME_MESSAGE.replace("%PROJECT%", config.project || "default"));
30
+
31
+ let isClosing = false;
32
+
33
+ const rl = readline.createInterface({
34
+ input: process.stdin,
35
+ output: process.stdout,
36
+ prompt: "rax-flow > ",
37
+ completer: (line: string) => {
38
+ const completions = getCompletions(line, context);
39
+ const hits = completions.filter((c) => c.startsWith(line));
40
+ return [hits.length ? hits : completions, line];
41
+ },
42
+ });
43
+
44
+ const unsubscribe = subscribeToEvents((event) => {
45
+ });
46
+
47
+ rl.on("line", async (input: string) => {
48
+ const trimmed = input.trim();
49
+ if (!trimmed) {
50
+ rl.prompt();
51
+ return;
52
+ }
53
+
54
+ history.add(trimmed);
55
+
56
+ const command = parseCommand(trimmed);
57
+
58
+ if (command.name === "exit" || command.name === "quit") {
59
+ isClosing = true;
60
+ console.log("👋 À bientôt !");
61
+ unsubscribe();
62
+ rl.close();
63
+ return;
64
+ }
65
+
66
+ const cmdDef = commands.get(command.name) || commands.get("help");
67
+ if (cmdDef) {
68
+ try {
69
+ await cmdDef.handler(command.args, command.flags, context);
70
+ } catch (error) {
71
+ console.error(`❌ Erreur: ${error instanceof Error ? error.message : String(error)}`);
72
+ }
73
+ } else {
74
+ console.log(`Commande inconnue: ${command.name}. Tapez 'help' pour voir les commandes disponibles.`);
75
+ }
76
+
77
+ if (!isClosing) {
78
+ rl.prompt();
79
+ }
80
+ });
81
+
82
+ rl.on("close", async () => {
83
+ if (!isClosing) {
84
+ await history.save();
85
+ console.log("\n👋 À bientôt !");
86
+ unsubscribe();
87
+ }
88
+ process.exit(0);
89
+ });
90
+
91
+ process.on("SIGINT", () => {
92
+ console.log("\n");
93
+ rl.prompt();
94
+ });
95
+
96
+ rl.prompt();
97
+ }
98
+
99
+ export async function startHubOneShot(command: string, args: string[]): Promise<void> {
100
+ const cwd = process.cwd();
101
+ const config = await loadConfig(cwd);
102
+ const context: HubContext = { config };
103
+ const commands = getCommandRegistry();
104
+
105
+ const parsed = parseCommand([command, ...args].join(" "));
106
+ const cmdDef = commands.get(parsed.name);
107
+
108
+ if (!cmdDef) {
109
+ console.error(`Commande inconnue: ${parsed.name}`);
110
+ process.exit(1);
111
+ }
112
+
113
+ try {
114
+ await cmdDef.handler(parsed.args, parsed.flags, context);
115
+ process.exit(0);
116
+ } catch (error) {
117
+ console.error(`❌ Erreur: ${error instanceof Error ? error.message : String(error)}`);
118
+ process.exit(1);
119
+ }
120
+ }
@@ -0,0 +1,107 @@
1
+ import { Command } from "./types.js";
2
+
3
+ const BOOLEAN_FLAGS = new Set([
4
+ "stream",
5
+ "json",
6
+ "f",
7
+ "force",
8
+ "verbose",
9
+ "quiet",
10
+ "dry-run",
11
+ "yes",
12
+ "help",
13
+ ]);
14
+
15
+ export function parseCommand(input: string): Command {
16
+ const tokens = input.trim().split(/\s+/);
17
+ const name = tokens[0] || "";
18
+ const args: string[] = [];
19
+ const flags: Record<string, string | boolean> = {};
20
+
21
+ for (let i = 1; i < tokens.length; i++) {
22
+ const token = tokens[i];
23
+ if (token.startsWith("--")) {
24
+ const flagName = token.slice(2);
25
+ const nextToken = tokens[i + 1];
26
+ if (nextToken && !nextToken.startsWith("-") && !BOOLEAN_FLAGS.has(flagName)) {
27
+ flags[flagName] = nextToken;
28
+ i++;
29
+ } else {
30
+ flags[flagName] = true;
31
+ }
32
+ } else if (token.startsWith("-")) {
33
+ const flagName = token.slice(1);
34
+ const nextToken = tokens[i + 1];
35
+ if (nextToken && !nextToken.startsWith("-") && !BOOLEAN_FLAGS.has(flagName)) {
36
+ flags[flagName] = nextToken;
37
+ i++;
38
+ } else {
39
+ flags[flagName] = true;
40
+ }
41
+ } else {
42
+ args.push(token);
43
+ }
44
+ }
45
+
46
+ return { name, args, flags };
47
+ }
48
+
49
+ export function getCompletions(partial: string, _context?: unknown): string[] {
50
+ const commands = [
51
+ "run",
52
+ "status",
53
+ "agents",
54
+ "providers",
55
+ "workflows",
56
+ "logs",
57
+ "metrics",
58
+ "memory",
59
+ "install",
60
+ "config",
61
+ "doctor",
62
+ "bridge-test",
63
+ "benchmark",
64
+ "evolve",
65
+ "dashboard",
66
+ "ui",
67
+ "chat",
68
+ "help",
69
+ "exit",
70
+ "quit",
71
+ ];
72
+
73
+ if (!partial) {
74
+ return commands;
75
+ }
76
+
77
+ const trimmed = partial.trim();
78
+ const endsWithSpace = partial.endsWith(" ");
79
+ const tokens = trimmed.split(/\s+/);
80
+ const currentWord = endsWithSpace ? "" : tokens[tokens.length - 1];
81
+
82
+ if (tokens.length === 1 && !endsWithSpace) {
83
+ return commands.filter((c) => c.startsWith(currentWord));
84
+ }
85
+
86
+ const command = tokens[0];
87
+ const isKnownCommand = commands.includes(command);
88
+
89
+ if (!isKnownCommand) {
90
+ return [];
91
+ }
92
+
93
+ switch (command) {
94
+ case "run":
95
+ return ["--workflow", "--max-parallel", "--stream", "--json"].filter((c) =>
96
+ c.startsWith(currentWord)
97
+ );
98
+ case "logs":
99
+ return ["-f", "--agent", "--level"].filter((c) => c.startsWith(currentWord));
100
+ case "agents":
101
+ case "providers":
102
+ case "workflows":
103
+ return [];
104
+ default:
105
+ return [];
106
+ }
107
+ }
@@ -0,0 +1,74 @@
1
+ // RAX-FLOW Design System - Borders and Boxes
2
+ // Brutalist style: no border-radius, sharp corners
3
+
4
+ export const borders = {
5
+ // Border characters for ASCII boxes
6
+ horizontal: "─",
7
+ vertical: "│",
8
+ topLeft: "┌",
9
+ topRight: "┐",
10
+ bottomLeft: "└",
11
+ bottomRight: "┘",
12
+ leftT: "├",
13
+ rightT: "┤",
14
+ topT: "┬",
15
+ bottomT: "┴",
16
+ cross: "┼",
17
+
18
+ // Double line (for emphasis)
19
+ doubleHorizontal: "═",
20
+ doubleVertical: "║",
21
+ doubleTopLeft: "╔",
22
+ doubleTopRight: "╗",
23
+ doubleBottomLeft: "╚",
24
+ doubleBottomRight: "╝",
25
+ };
26
+
27
+ // Box drawing utilities
28
+ export function drawBox(content: string[], width: number, title?: string): string {
29
+ const { topLeft, topRight, bottomLeft, bottomRight, horizontal, vertical } = borders;
30
+
31
+ const lines: string[] = [];
32
+
33
+ // Top border
34
+ if (title) {
35
+ const titleStr = ` ${title} `;
36
+ const sideWidth = Math.floor((width - titleStr.length - 2) / 2);
37
+ const leftSide = horizontal.repeat(sideWidth);
38
+ const rightSide = horizontal.repeat(width - titleStr.length - 2 - sideWidth);
39
+ lines.push(`${topLeft}${leftSide}${titleStr}${rightSide}${topRight}`);
40
+ } else {
41
+ lines.push(`${topLeft}${horizontal.repeat(width - 2)}${topRight}`);
42
+ }
43
+
44
+ // Content
45
+ for (const line of content) {
46
+ const padded = line.padEnd(width - 2, " ").slice(0, width - 2);
47
+ lines.push(`${vertical}${padded}${vertical}`);
48
+ }
49
+
50
+ // Bottom border
51
+ lines.push(`${bottomLeft}${horizontal.repeat(width - 2)}${bottomRight}`);
52
+
53
+ return lines.join("\n");
54
+ }
55
+
56
+ export function drawSeparator(width: number, title?: string): string {
57
+ const { leftT, rightT, horizontal } = borders;
58
+
59
+ if (title) {
60
+ const titleStr = ` ${title} `;
61
+ const sideWidth = Math.floor((width - titleStr.length - 2) / 2);
62
+ const leftSide = horizontal.repeat(sideWidth);
63
+ const rightSide = horizontal.repeat(width - titleStr.length - 2 - sideWidth);
64
+ return `${leftT}${leftSide}${titleStr}${rightSide}${rightT}`;
65
+ }
66
+
67
+ return `${leftT}${horizontal.repeat(width - 2)}${rightT}`;
68
+ }
69
+
70
+ export function drawProgressBar(percent: number, width: number = 20): string {
71
+ const filled = Math.floor((percent / 100) * width);
72
+ const empty = width - filled;
73
+ return "█".repeat(filled) + "░".repeat(empty);
74
+ }
@@ -0,0 +1,129 @@
1
+ // RAX-FLOW Design System - Colors
2
+ // Based on cli-design.md specifications
3
+
4
+ export const colors = {
5
+ // Backgrounds
6
+ background: "#050505",
7
+ surface: "#0a0a0a",
8
+ surfaceElev: "#0d0d0d",
9
+
10
+ // Primary
11
+ primary: "#f97316", // Orange vif
12
+ primaryGlow: "rgba(249, 115, 22, 0.3)",
13
+ primaryGlowHover: "rgba(249, 115, 22, 0.5)",
14
+
15
+ // Text
16
+ textPrimary: "#ffffff",
17
+ textSecondary: "#a1a1aa",
18
+ textTertiary: "#71717a",
19
+ textQuaternary: "#3f3f46",
20
+
21
+ // Status
22
+ success: "#22c55e",
23
+ warning: "#f59e0b",
24
+ error: "#ef4444",
25
+
26
+ // Borders
27
+ border: "#27272a",
28
+
29
+ // Mutations
30
+ mutation: "#f59e0b",
31
+ mutationGlow: "rgba(245, 158, 11, 0.4)",
32
+ };
33
+
34
+ // ANSI color codes for terminal
35
+ export const ansiColors = {
36
+ reset: "\x1b[0m",
37
+ bright: "\x1b[1m",
38
+ dim: "\x1b[2m",
39
+
40
+ // Foreground colors
41
+ black: "\x1b[30m",
42
+ red: "\x1b[31m",
43
+ green: "\x1b[32m",
44
+ yellow: "\x1b[33m",
45
+ blue: "\x1b[34m",
46
+ magenta: "\x1b[35m",
47
+ cyan: "\x1b[36m",
48
+ white: "\x1b[37m",
49
+ gray: "\x1b[90m",
50
+
51
+ // Bright colors
52
+ brightRed: "\x1b[91m",
53
+ brightGreen: "\x1b[92m",
54
+ brightYellow: "\x1b[93m",
55
+ brightBlue: "\x1b[94m",
56
+ brightMagenta: "\x1b[95m",
57
+ brightCyan: "\x1b[96m",
58
+ brightWhite: "\x1b[97m",
59
+
60
+ // Background colors
61
+ bgBlack: "\x1b[40m",
62
+ bgRed: "\x1b[41m",
63
+ bgGreen: "\x1b[42m",
64
+ bgYellow: "\x1b[43m",
65
+ bgBlue: "\x1b[44m",
66
+ bgMagenta: "\x1b[45m",
67
+ bgCyan: "\x1b[46m",
68
+ bgWhite: "\x1b[47m",
69
+ bgGray: "\x1b[100m",
70
+ };
71
+
72
+ // Status indicators
73
+ export const statusIndicators = {
74
+ online: "●",
75
+ offline: "○",
76
+ running: "▶",
77
+ loading: "◐",
78
+ mutation: "◆",
79
+ checkpoint: "■",
80
+ pending: "○",
81
+ done: "✓",
82
+ };
83
+
84
+ // Provider indicators
85
+ export const providerIndicators: Record<string, string> = {
86
+ host: "[H]",
87
+ claude: "[C]",
88
+ opencode: "[O]",
89
+ kilo: "[K]",
90
+ anthropic: "[A]",
91
+ gemini: "[G]",
92
+ mistral: "[M]",
93
+ groq: "[Q]",
94
+ openai: "[O]",
95
+ };
96
+
97
+ // Utility functions
98
+ export function colorize(text: string, color: keyof typeof ansiColors): string {
99
+ return `${ansiColors[color]}${text}${ansiColors.reset}`;
100
+ }
101
+
102
+ export function statusColor(status: string): string {
103
+ switch (status.toLowerCase()) {
104
+ case "online":
105
+ case "ready":
106
+ case "active":
107
+ case "done":
108
+ case "success":
109
+ return ansiColors.green;
110
+ case "running":
111
+ case "busy":
112
+ return ansiColors.yellow;
113
+ case "error":
114
+ case "failed":
115
+ return ansiColors.red;
116
+ case "queued":
117
+ case "pending":
118
+ case "idle":
119
+ return ansiColors.gray;
120
+ default:
121
+ return ansiColors.reset;
122
+ }
123
+ }
124
+
125
+ export function formatStatus(status: string): string {
126
+ const indicator = statusIndicators[status.toLowerCase() as keyof typeof statusIndicators] || "○";
127
+ const color = statusColor(status);
128
+ return `${color}${indicator}${ansiColors.reset}`;
129
+ }