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.
- package/LICENSE +21 -0
- package/dist/bin.js +27 -3
- package/dist/bin.js.map +1 -1
- package/dist/hub/__tests__/commands.test.d.ts.map +1 -0
- package/dist/hub/__tests__/commands.test.js +72 -0
- package/dist/hub/__tests__/commands.test.js.map +1 -0
- package/dist/hub/__tests__/history.test.d.ts.map +1 -0
- package/dist/hub/__tests__/history.test.js +119 -0
- package/dist/hub/__tests__/history.test.js.map +1 -0
- package/dist/hub/__tests__/parser.test.d.ts.map +1 -0
- package/dist/hub/__tests__/parser.test.js +92 -0
- package/dist/hub/__tests__/parser.test.js.map +1 -0
- package/dist/hub/chat/ChatApp.d.ts +2 -0
- package/dist/hub/chat/ChatApp.d.ts.map +1 -0
- package/dist/hub/chat/ChatApp.js +146 -0
- package/dist/hub/chat/ChatApp.js.map +1 -0
- package/dist/hub/chat/components/ChatInput.d.ts +9 -0
- package/dist/hub/chat/components/ChatInput.d.ts.map +1 -0
- package/dist/hub/chat/components/ChatInput.js +19 -0
- package/dist/hub/chat/components/ChatInput.js.map +1 -0
- package/dist/hub/chat/components/MessageList.d.ts +7 -0
- package/dist/hub/chat/components/MessageList.d.ts.map +1 -0
- package/dist/hub/chat/components/MessageList.js +6 -0
- package/dist/hub/chat/components/MessageList.js.map +1 -0
- package/dist/hub/chat/context.d.ts.map +1 -0
- package/dist/hub/chat/context.js +42 -0
- package/dist/hub/chat/context.js.map +1 -0
- package/dist/hub/chat/hooks/useChatHistory.d.ts +7 -0
- package/dist/hub/chat/hooks/useChatHistory.d.ts.map +1 -0
- package/dist/hub/chat/hooks/useChatHistory.js +31 -0
- package/dist/hub/chat/hooks/useChatHistory.js.map +1 -0
- package/dist/hub/chat/index.d.ts.map +1 -0
- package/dist/hub/chat/index.js +7 -0
- package/dist/hub/chat/index.js.map +1 -0
- package/dist/hub/chat/intent-parser.d.ts.map +1 -0
- package/dist/hub/chat/intent-parser.js +48 -0
- package/dist/hub/chat/intent-parser.js.map +1 -0
- package/dist/hub/chat/types.d.ts.map +1 -0
- package/dist/hub/chat/types.js +2 -0
- package/dist/hub/chat/types.js.map +1 -0
- package/dist/hub/commands/agents.d.ts.map +1 -0
- package/dist/hub/commands/agents.js +36 -0
- package/dist/hub/commands/agents.js.map +1 -0
- package/dist/hub/commands/index.d.ts.map +1 -0
- package/dist/hub/commands/index.js +120 -0
- package/dist/hub/commands/index.js.map +1 -0
- package/dist/hub/commands/logs.d.ts.map +1 -0
- package/dist/hub/commands/logs.js +53 -0
- package/dist/hub/commands/logs.js.map +1 -0
- package/dist/hub/commands/memory.d.ts.map +1 -0
- package/dist/hub/commands/memory.js +40 -0
- package/dist/hub/commands/memory.js.map +1 -0
- package/dist/hub/commands/metrics.d.ts.map +1 -0
- package/dist/hub/commands/metrics.js +35 -0
- package/dist/hub/commands/metrics.js.map +1 -0
- package/dist/hub/commands/providers.d.ts.map +1 -0
- package/dist/hub/commands/providers.js +26 -0
- package/dist/hub/commands/providers.js.map +1 -0
- package/dist/hub/commands/run.d.ts.map +1 -0
- package/dist/hub/commands/run.js +31 -0
- package/dist/hub/commands/run.js.map +1 -0
- package/dist/hub/commands/status.d.ts.map +1 -0
- package/dist/hub/commands/status.js +61 -0
- package/dist/hub/commands/status.js.map +1 -0
- package/dist/hub/commands/workflows.d.ts.map +1 -0
- package/dist/hub/commands/workflows.js +45 -0
- package/dist/hub/commands/workflows.js.map +1 -0
- package/dist/hub/config-loader.d.ts.map +1 -0
- package/dist/hub/config-loader.js +27 -0
- package/dist/hub/config-loader.js.map +1 -0
- package/dist/hub/event-listener.d.ts.map +1 -0
- package/dist/hub/event-listener.js +8 -0
- package/dist/hub/event-listener.js.map +1 -0
- package/dist/hub/history.d.ts.map +1 -0
- package/dist/hub/history.js +59 -0
- package/dist/hub/history.js.map +1 -0
- package/dist/hub/index.d.ts.map +1 -0
- package/dist/hub/index.js +102 -0
- package/dist/hub/index.js.map +1 -0
- package/dist/hub/parser.d.ts.map +1 -0
- package/dist/hub/parser.js +98 -0
- package/dist/hub/parser.js.map +1 -0
- package/dist/hub/styles/borders.d.ts.map +1 -0
- package/dist/hub/styles/borders.js +64 -0
- package/dist/hub/styles/borders.js.map +1 -0
- package/dist/hub/styles/colors.d.ts.map +1 -0
- package/dist/hub/styles/colors.js +115 -0
- package/dist/hub/styles/colors.js.map +1 -0
- package/dist/hub/styles/typography.d.ts.map +1 -0
- package/dist/hub/styles/typography.js +60 -0
- package/dist/hub/styles/typography.js.map +1 -0
- package/dist/hub/tui/App.d.ts +2 -0
- package/dist/hub/tui/App.d.ts.map +1 -0
- package/dist/hub/tui/App.js +53 -0
- package/dist/hub/tui/App.js.map +1 -0
- package/dist/hub/tui/components/AgentQueue.d.ts +6 -0
- package/dist/hub/tui/components/AgentQueue.d.ts.map +1 -0
- package/dist/hub/tui/components/AgentQueue.js +20 -0
- package/dist/hub/tui/components/AgentQueue.js.map +1 -0
- package/dist/hub/tui/components/DAGPanel.d.ts +16 -0
- package/dist/hub/tui/components/DAGPanel.d.ts.map +1 -0
- package/dist/hub/tui/components/DAGPanel.js +51 -0
- package/dist/hub/tui/components/DAGPanel.js.map +1 -0
- package/dist/hub/tui/components/Header.d.ts +7 -0
- package/dist/hub/tui/components/Header.d.ts.map +1 -0
- package/dist/hub/tui/components/Header.js +17 -0
- package/dist/hub/tui/components/Header.js.map +1 -0
- package/dist/hub/tui/components/LogsPanel.d.ts +6 -0
- package/dist/hub/tui/components/LogsPanel.d.ts.map +1 -0
- package/dist/hub/tui/components/LogsPanel.js +26 -0
- package/dist/hub/tui/components/LogsPanel.js.map +1 -0
- package/dist/hub/tui/components/StatusBar.d.ts +8 -0
- package/dist/hub/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/hub/tui/components/StatusBar.js +7 -0
- package/dist/hub/tui/components/StatusBar.js.map +1 -0
- package/dist/hub/tui/hooks/useEvents.d.ts +2 -0
- package/dist/hub/tui/hooks/useEvents.d.ts.map +1 -0
- package/dist/hub/tui/hooks/useEvents.js +13 -0
- package/dist/hub/tui/hooks/useEvents.js.map +1 -0
- package/dist/hub/tui/index.d.ts.map +1 -0
- package/dist/hub/tui/index.js +7 -0
- package/dist/hub/tui/index.js.map +1 -0
- package/dist/hub/tui/types.d.ts.map +1 -0
- package/dist/hub/tui/types.js +2 -0
- package/dist/hub/tui/types.js.map +1 -0
- package/dist/hub/types.d.ts.map +1 -0
- package/dist/hub/types.js +2 -0
- package/dist/hub/types.js.map +1 -0
- package/dist/tui/App.d.ts +2 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +31 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/components/ChatPanel.d.ts +14 -0
- package/dist/tui/components/ChatPanel.d.ts.map +1 -0
- package/dist/tui/components/ChatPanel.js +30 -0
- package/dist/tui/components/ChatPanel.js.map +1 -0
- package/dist/tui/components/Header.d.ts +9 -0
- package/dist/tui/components/Header.d.ts.map +1 -0
- package/dist/tui/components/Header.js +17 -0
- package/dist/tui/components/Header.js.map +1 -0
- package/dist/tui/components/InputBar.d.ts +8 -0
- package/dist/tui/components/InputBar.d.ts.map +1 -0
- package/dist/tui/components/InputBar.js +16 -0
- package/dist/tui/components/InputBar.js.map +1 -0
- package/dist/tui/components/StatusPanel.d.ts +20 -0
- package/dist/tui/components/StatusPanel.d.ts.map +1 -0
- package/dist/tui/components/StatusPanel.js +20 -0
- package/dist/tui/components/StatusPanel.js.map +1 -0
- package/dist/tui/hooks/useAppState.d.ts +38 -0
- package/dist/tui/hooks/useAppState.d.ts.map +1 -0
- package/dist/tui/hooks/useAppState.js +127 -0
- package/dist/tui/hooks/useAppState.js.map +1 -0
- package/dist/tui/index.d.ts +3 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +8 -0
- package/dist/tui/index.js.map +1 -0
- package/package.json +17 -11
- package/src/bin.ts +29 -3
- package/src/hub/__tests__/commands.test.ts +84 -0
- package/src/hub/__tests__/history.test.ts +137 -0
- package/src/hub/__tests__/parser.test.ts +105 -0
- package/src/hub/commands/agents.ts +53 -0
- package/src/hub/commands/index.ts +137 -0
- package/src/hub/commands/logs.ts +70 -0
- package/src/hub/commands/memory.ts +47 -0
- package/src/hub/commands/metrics.ts +49 -0
- package/src/hub/commands/providers.ts +39 -0
- package/src/hub/commands/run.ts +37 -0
- package/src/hub/commands/status.ts +69 -0
- package/src/hub/commands/workflows.ts +64 -0
- package/src/hub/config-loader.ts +37 -0
- package/src/hub/event-listener.ts +13 -0
- package/src/hub/history.ts +66 -0
- package/src/hub/index.ts +120 -0
- package/src/hub/parser.ts +107 -0
- package/src/hub/styles/borders.ts +74 -0
- package/src/hub/styles/colors.ts +129 -0
- package/src/hub/styles/typography.ts +68 -0
- package/src/hub/types.ts +31 -0
- package/src/tui/App.tsx +61 -0
- package/src/tui/components/ChatPanel.tsx +79 -0
- package/src/tui/components/Header.tsx +53 -0
- package/src/tui/components/InputBar.tsx +55 -0
- package/src/tui/components/StatusPanel.tsx +85 -0
- package/src/tui/hooks/useAppState.ts +168 -0
- package/src/tui/index.ts +9 -0
- package/tsconfig.json +19 -3
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/benchmark.d.ts +0 -10
- package/dist/bin.d.ts +0 -3
- package/dist/bootstrap.d.ts +0 -8
- package/dist/bridge-adapter-templates.d.ts +0 -4
- package/dist/bridge-test.d.ts +0 -7
- package/dist/dashboard.d.ts +0 -4
- package/dist/doctor.d.ts +0 -6
- package/dist/evolve.d.ts +0 -7
- package/dist/host-init-templates.d.ts +0 -16
- package/dist/index.d.ts +0 -11
- package/dist/init-host.d.ts +0 -10
- package/dist/install.d.ts +0 -8
- package/dist/run.d.ts +0 -16
- package/dist/styles.d.ts +0 -12
- package/dist/vendor-manifests.d.ts +0 -22
- package/package/dashboard/index.html +0 -420
- package/package/package.json +0 -28
- package/package/src/benchmark.ts +0 -156
- package/package/src/bin.ts +0 -127
- package/package/src/bootstrap.ts +0 -36
- package/package/src/bridge-adapter-templates.ts +0 -181
- package/package/src/bridge-test.ts +0 -107
- package/package/src/dashboard.ts +0 -51
- package/package/src/doctor.ts +0 -92
- package/package/src/evolve.ts +0 -74
- package/package/src/host-init-templates.ts +0 -134
- package/package/src/index.ts +0 -10
- package/package/src/init-host.ts +0 -285
- package/package/src/install.ts +0 -118
- package/package/src/run.ts +0 -317
- package/package/src/styles.ts +0 -12
- package/package/src/vendor-manifests.ts +0 -113
- package/package/src/ws-relay.ts +0 -156
- package/package/tsconfig.json +0 -12
- 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
|
+
}
|
package/src/hub/index.ts
ADDED
|
@@ -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
|
+
}
|