rax-flow 0.1.8 → 0.2.0
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/bin.js +8 -6
- package/dist/bin.js.map +1 -1
- package/dist/hub/commands/index.d.ts.map +1 -1
- package/dist/hub/commands/index.js +7 -4
- package/dist/hub/commands/index.js.map +1 -1
- package/dist/hub/event-listener.d.ts +6 -0
- package/dist/hub/event-listener.d.ts.map +1 -1
- package/dist/hub/event-listener.js +10 -6
- package/dist/hub/event-listener.js.map +1 -1
- package/dist/hub/index.d.ts.map +1 -1
- package/dist/hub/index.js +12 -0
- package/dist/hub/index.js.map +1 -1
- package/dist/setup/components/ApiKeyInput.d.ts +25 -0
- package/dist/setup/components/ApiKeyInput.d.ts.map +1 -0
- package/dist/setup/components/ApiKeyInput.js +54 -0
- package/dist/setup/components/ApiKeyInput.js.map +1 -0
- package/dist/setup/components/AsciiBanner.d.ts +22 -0
- package/dist/setup/components/AsciiBanner.d.ts.map +1 -0
- package/dist/setup/components/AsciiBanner.js +55 -0
- package/dist/setup/components/AsciiBanner.js.map +1 -0
- package/dist/setup/components/CliDetector.d.ts +17 -0
- package/dist/setup/components/CliDetector.d.ts.map +1 -0
- package/dist/setup/components/CliDetector.js +79 -0
- package/dist/setup/components/CliDetector.js.map +1 -0
- package/dist/setup/components/ModeSelector.d.ts +8 -0
- package/dist/setup/components/ModeSelector.d.ts.map +1 -0
- package/dist/setup/components/ModeSelector.js +76 -0
- package/dist/setup/components/ModeSelector.js.map +1 -0
- package/dist/setup/components/ProviderSelector.d.ts +18 -0
- package/dist/setup/components/ProviderSelector.d.ts.map +1 -0
- package/dist/setup/components/ProviderSelector.js +97 -0
- package/dist/setup/components/ProviderSelector.js.map +1 -0
- package/dist/setup/components/SetupWizard.d.ts +2 -0
- package/dist/setup/components/SetupWizard.d.ts.map +1 -0
- package/dist/setup/components/SetupWizard.js +212 -0
- package/dist/setup/components/SetupWizard.js.map +1 -0
- package/dist/setup/components/StepIndicator.d.ts +13 -0
- package/dist/setup/components/StepIndicator.d.ts.map +1 -0
- package/dist/setup/components/StepIndicator.js +18 -0
- package/dist/setup/components/StepIndicator.js.map +1 -0
- package/dist/setup/components/SuccessScreen.d.ts +18 -0
- package/dist/setup/components/SuccessScreen.d.ts.map +1 -0
- package/dist/setup/components/SuccessScreen.js +38 -0
- package/dist/setup/components/SuccessScreen.js.map +1 -0
- package/dist/setup/index.d.ts +12 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +29 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/utils/cli-detection.d.ts +12 -0
- package/dist/setup/utils/cli-detection.d.ts.map +1 -0
- package/dist/setup/utils/cli-detection.js +83 -0
- package/dist/setup/utils/cli-detection.js.map +1 -0
- package/dist/setup/utils/config-writer.d.ts +43 -0
- package/dist/setup/utils/config-writer.d.ts.map +1 -0
- package/dist/setup/utils/config-writer.js +180 -0
- package/dist/setup/utils/config-writer.js.map +1 -0
- package/dist/tui/App.d.ts +2 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +88 -20
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/AgentStateIcon.d.ts +18 -0
- package/dist/tui/components/AgentStateIcon.d.ts.map +1 -0
- package/dist/tui/components/AgentStateIcon.js +57 -0
- package/dist/tui/components/AgentStateIcon.js.map +1 -0
- package/dist/tui/components/AnimatedBranch.d.ts +39 -0
- package/dist/tui/components/AnimatedBranch.d.ts.map +1 -0
- package/dist/tui/components/AnimatedBranch.js +64 -0
- package/dist/tui/components/AnimatedBranch.js.map +1 -0
- package/dist/tui/components/ChatPanel.d.ts +2 -1
- package/dist/tui/components/ChatPanel.d.ts.map +1 -1
- package/dist/tui/components/ChatPanel.js +47 -28
- package/dist/tui/components/ChatPanel.js.map +1 -1
- package/dist/tui/components/DAGPanel.d.ts +14 -2
- package/dist/tui/components/DAGPanel.d.ts.map +1 -1
- package/dist/tui/components/DAGPanel.js +48 -27
- package/dist/tui/components/DAGPanel.js.map +1 -1
- package/dist/tui/components/ExecutionTimeline.d.ts +34 -0
- package/dist/tui/components/ExecutionTimeline.d.ts.map +1 -0
- package/dist/tui/components/ExecutionTimeline.js +67 -0
- package/dist/tui/components/ExecutionTimeline.js.map +1 -0
- package/dist/tui/components/Header.d.ts +2 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +26 -19
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/HelpOverlay.d.ts +2 -1
- package/dist/tui/components/HelpOverlay.d.ts.map +1 -1
- package/dist/tui/components/HelpOverlay.js +59 -41
- package/dist/tui/components/HelpOverlay.js.map +1 -1
- package/dist/tui/components/InputBar.d.ts +3 -1
- package/dist/tui/components/InputBar.d.ts.map +1 -1
- package/dist/tui/components/InputBar.js +12 -7
- package/dist/tui/components/InputBar.js.map +1 -1
- package/dist/tui/components/LogsPanel.d.ts +9 -0
- package/dist/tui/components/LogsPanel.d.ts.map +1 -0
- package/dist/tui/components/LogsPanel.js +56 -0
- package/dist/tui/components/LogsPanel.js.map +1 -0
- package/dist/tui/components/MemoryPanel.d.ts +21 -0
- package/dist/tui/components/MemoryPanel.d.ts.map +1 -0
- package/dist/tui/components/MemoryPanel.js +51 -0
- package/dist/tui/components/MemoryPanel.js.map +1 -0
- package/dist/tui/components/MetricsPanel.d.ts +18 -0
- package/dist/tui/components/MetricsPanel.d.ts.map +1 -0
- package/dist/tui/components/MetricsPanel.js +27 -0
- package/dist/tui/components/MetricsPanel.js.map +1 -0
- package/dist/tui/components/StatusPanel.d.ts +3 -1
- package/dist/tui/components/StatusPanel.d.ts.map +1 -1
- package/dist/tui/components/StatusPanel.js +20 -18
- package/dist/tui/components/StatusPanel.js.map +1 -1
- package/dist/tui/components/TaskTree.d.ts +28 -0
- package/dist/tui/components/TaskTree.d.ts.map +1 -0
- package/dist/tui/components/TaskTree.js +29 -0
- package/dist/tui/components/TaskTree.js.map +1 -0
- package/dist/tui/components/animations/ProgressBar.d.ts +39 -0
- package/dist/tui/components/animations/ProgressBar.d.ts.map +1 -0
- package/dist/tui/components/animations/ProgressBar.js +39 -0
- package/dist/tui/components/animations/ProgressBar.js.map +1 -0
- package/dist/tui/components/animations/Pulse.d.ts +17 -0
- package/dist/tui/components/animations/Pulse.d.ts.map +1 -0
- package/dist/tui/components/animations/Pulse.js +47 -0
- package/dist/tui/components/animations/Pulse.js.map +1 -0
- package/dist/tui/components/animations/Spinner.d.ts +13 -0
- package/dist/tui/components/animations/Spinner.d.ts.map +1 -0
- package/dist/tui/components/animations/Spinner.js +36 -0
- package/dist/tui/components/animations/Spinner.js.map +1 -0
- package/dist/tui/components/animations/StatusAnimator.d.ts +27 -0
- package/dist/tui/components/animations/StatusAnimator.d.ts.map +1 -0
- package/dist/tui/components/animations/StatusAnimator.js +85 -0
- package/dist/tui/components/animations/StatusAnimator.js.map +1 -0
- package/dist/tui/components/animations/TypingEffect.d.ts +26 -0
- package/dist/tui/components/animations/TypingEffect.d.ts.map +1 -0
- package/dist/tui/components/animations/TypingEffect.js +59 -0
- package/dist/tui/components/animations/TypingEffect.js.map +1 -0
- package/dist/tui/components/animations/index.d.ts +8 -0
- package/dist/tui/components/animations/index.d.ts.map +1 -0
- package/dist/tui/components/animations/index.js +6 -0
- package/dist/tui/components/animations/index.js.map +1 -0
- package/dist/tui/hooks/useAnimation.d.ts +42 -0
- package/dist/tui/hooks/useAnimation.d.ts.map +1 -0
- package/dist/tui/hooks/useAnimation.js +212 -0
- package/dist/tui/hooks/useAnimation.js.map +1 -0
- package/dist/tui/hooks/useAppState.d.ts +10 -0
- package/dist/tui/hooks/useAppState.d.ts.map +1 -1
- package/dist/tui/hooks/useAppState.js +178 -75
- package/dist/tui/hooks/useAppState.js.map +1 -1
- package/dist/tui/services/orchestrator.d.ts +16 -0
- package/dist/tui/services/orchestrator.d.ts.map +1 -0
- package/dist/tui/services/orchestrator.js +152 -0
- package/dist/tui/services/orchestrator.js.map +1 -0
- package/dist/tui/styles/borders.d.ts +31 -0
- package/dist/tui/styles/borders.d.ts.map +1 -0
- package/dist/tui/styles/borders.js +47 -0
- package/dist/tui/styles/borders.js.map +1 -0
- package/dist/tui/styles/colors.d.ts +18 -0
- package/dist/tui/styles/colors.d.ts.map +1 -0
- package/dist/tui/styles/colors.js +18 -0
- package/dist/tui/styles/colors.js.map +1 -0
- package/dist/tui/styles/index.d.ts +6 -0
- package/dist/tui/styles/index.d.ts.map +1 -0
- package/dist/tui/styles/index.js +6 -0
- package/dist/tui/styles/index.js.map +1 -0
- package/dist/tui/styles/indicators.d.ts +67 -0
- package/dist/tui/styles/indicators.d.ts.map +1 -0
- package/dist/tui/styles/indicators.js +42 -0
- package/dist/tui/styles/indicators.js.map +1 -0
- package/dist/tui/styles/layout.d.ts +21 -0
- package/dist/tui/styles/layout.d.ts.map +1 -0
- package/dist/tui/styles/layout.js +42 -0
- package/dist/tui/styles/layout.js.map +1 -0
- package/dist/tui/styles/providers.d.ts +77 -0
- package/dist/tui/styles/providers.d.ts.map +1 -0
- package/dist/tui/styles/providers.js +31 -0
- package/dist/tui/styles/providers.js.map +1 -0
- package/dist/tui/utils/animation.d.ts +44 -0
- package/dist/tui/utils/animation.d.ts.map +1 -0
- package/dist/tui/utils/animation.js +107 -0
- package/dist/tui/utils/animation.js.map +1 -0
- package/package.json +8 -8
- package/src/bin.ts +8 -5
- package/src/hub/commands/index.ts +7 -4
- package/src/hub/event-listener.ts +14 -10
- package/src/hub/index.ts +14 -2
- package/src/setup/components/ApiKeyInput.tsx +158 -0
- package/src/setup/components/AsciiBanner.tsx +125 -0
- package/src/setup/components/CliDetector.tsx +230 -0
- package/src/setup/components/ModeSelector.tsx +137 -0
- package/src/setup/components/ProviderSelector.tsx +174 -0
- package/src/setup/components/SetupWizard.tsx +368 -0
- package/src/setup/components/StepIndicator.tsx +74 -0
- package/src/setup/components/SuccessScreen.tsx +229 -0
- package/src/setup/index.ts +34 -0
- package/src/setup/utils/cli-detection.ts +99 -0
- package/src/setup/utils/config-writer.ts +249 -0
- package/src/tui/App.tsx +117 -53
- package/src/tui/components/AgentStateIcon.tsx +84 -0
- package/src/tui/components/AnimatedBranch.tsx +134 -0
- package/src/tui/components/ChatPanel.tsx +85 -43
- package/src/tui/components/DAGPanel.tsx +150 -58
- package/src/tui/components/ExecutionTimeline.tsx +225 -0
- package/src/tui/components/Header.tsx +76 -43
- package/src/tui/components/HelpOverlay.tsx +118 -61
- package/src/tui/components/InputBar.tsx +33 -19
- package/src/tui/components/LogsPanel.tsx +129 -0
- package/src/tui/components/MemoryPanel.tsx +163 -0
- package/src/tui/components/MetricsPanel.tsx +149 -0
- package/src/tui/components/StatusPanel.tsx +84 -37
- package/src/tui/components/TaskTree.tsx +159 -0
- package/src/tui/components/animations/ProgressBar.tsx +160 -0
- package/src/tui/components/animations/Pulse.tsx +73 -0
- package/src/tui/components/animations/Spinner.tsx +54 -0
- package/src/tui/components/animations/StatusAnimator.tsx +153 -0
- package/src/tui/components/animations/TypingEffect.tsx +119 -0
- package/src/tui/components/animations/index.ts +16 -0
- package/src/tui/hooks/useAnimation.ts +290 -0
- package/src/tui/hooks/useAppState.ts +206 -67
- package/src/tui/services/orchestrator.ts +195 -0
- package/src/tui/styles/borders.ts +51 -0
- package/src/tui/styles/colors.ts +19 -0
- package/src/tui/styles/index.ts +20 -0
- package/src/tui/styles/indicators.ts +54 -0
- package/src/tui/styles/layout.ts +44 -0
- package/src/tui/styles/providers.ts +32 -0
- package/src/tui/utils/animation.ts +124 -0
- package/LICENSE +0 -21
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useMemo, memo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
+
import { tuiColors, getStatusIndicator, getSpinnerFrame, treeChars } from "../styles/index.js";
|
|
4
|
+
import { AnimatedProgressBar } from "./animations/index.js";
|
|
5
|
+
import { AgentStateIcon, AgentState } from "./AgentStateIcon.js";
|
|
6
|
+
|
|
7
|
+
interface DAGSubtask {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
state: AgentState;
|
|
11
|
+
}
|
|
3
12
|
|
|
4
13
|
interface DAGNode {
|
|
5
14
|
id: string;
|
|
6
15
|
name: string;
|
|
7
16
|
status: "pending" | "running" | "done" | "error";
|
|
8
17
|
agent?: string;
|
|
18
|
+
state?: AgentState;
|
|
19
|
+
executionTime?: number;
|
|
20
|
+
detail?: string;
|
|
21
|
+
subtasks?: DAGSubtask[];
|
|
9
22
|
}
|
|
10
23
|
|
|
11
24
|
interface DAGLevel {
|
|
12
25
|
name: string;
|
|
13
26
|
progress: number;
|
|
14
27
|
nodes: DAGNode[];
|
|
28
|
+
status?: 'done' | 'running' | 'pending';
|
|
15
29
|
}
|
|
16
30
|
|
|
17
31
|
interface WorkflowState {
|
|
@@ -20,97 +34,175 @@ interface WorkflowState {
|
|
|
20
34
|
totalProgress: number;
|
|
21
35
|
}
|
|
22
36
|
|
|
23
|
-
interface
|
|
24
|
-
|
|
37
|
+
interface DAGNodeItemProps {
|
|
38
|
+
node: DAGNode;
|
|
25
39
|
tick: number;
|
|
26
|
-
|
|
40
|
+
isLast: boolean;
|
|
27
41
|
}
|
|
28
42
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
const STATE_LABELS: Record<AgentState, string> = {
|
|
44
|
+
idle: "pending",
|
|
45
|
+
thinking: "thinking...",
|
|
46
|
+
processing: "processing",
|
|
47
|
+
running: "running",
|
|
48
|
+
success: "done",
|
|
49
|
+
error: "error",
|
|
50
|
+
waiting: "waiting",
|
|
34
51
|
};
|
|
35
52
|
|
|
36
|
-
const
|
|
53
|
+
const DAGNodeItem = memo(function DAGNodeItem({ node, tick, isLast }: DAGNodeItemProps) {
|
|
54
|
+
const statusInfo = useMemo(() => getStatusIndicator(node.status), [node.status]);
|
|
55
|
+
const agentState = useMemo((): AgentState => {
|
|
56
|
+
if (node.state) return node.state;
|
|
57
|
+
if (node.status === 'running') return 'running';
|
|
58
|
+
if (node.status === 'done') return 'success';
|
|
59
|
+
if (node.status === 'error') return 'error';
|
|
60
|
+
return 'idle';
|
|
61
|
+
}, [node.state, node.status]);
|
|
62
|
+
|
|
63
|
+
const icon = node.status === "running"
|
|
64
|
+
? getSpinnerFrame(tick, "dots")
|
|
65
|
+
: statusInfo.icon;
|
|
66
|
+
const prefix = isLast ? treeChars.lastBranch : treeChars.branch;
|
|
67
|
+
const timeStr = node.executionTime ? `${node.executionTime.toFixed(1)}s` : "";
|
|
37
68
|
|
|
38
|
-
function ProgressBar({ progress, width = 20 }: { progress: number; width?: number }) {
|
|
39
|
-
const filled = Math.round((progress / 100) * width);
|
|
40
|
-
const empty = width - filled;
|
|
41
|
-
const bar = "█".repeat(filled) + "░".repeat(empty);
|
|
42
69
|
return (
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
<Box flexDirection="column">
|
|
71
|
+
<Box flexDirection="row">
|
|
72
|
+
<Text color={tuiColors.textTertiary}>{prefix} </Text>
|
|
73
|
+
<Box flexDirection="row">
|
|
74
|
+
<Text color={tuiColors.textSecondary}>[</Text>
|
|
75
|
+
<AgentStateIcon state={agentState} tick={tick} />
|
|
76
|
+
<Text color={tuiColors.textSecondary}>]</Text>
|
|
77
|
+
</Box>
|
|
78
|
+
<Text color={tuiColors.textPrimary}> {node.name.padEnd(18)}</Text>
|
|
79
|
+
{timeStr && (
|
|
80
|
+
<Text color={tuiColors.textTertiary}> ● {timeStr}</Text>
|
|
81
|
+
)}
|
|
82
|
+
</Box>
|
|
83
|
+
{node.detail && (
|
|
84
|
+
<Box flexDirection="row">
|
|
85
|
+
<Text color={tuiColors.textTertiary}> └── {node.detail}</Text>
|
|
86
|
+
</Box>
|
|
87
|
+
)}
|
|
88
|
+
{node.subtasks && node.subtasks.length > 0 && (
|
|
89
|
+
<Box flexDirection="column">
|
|
90
|
+
{node.subtasks.map((subtask, idx) => (
|
|
91
|
+
<Box key={subtask.id} flexDirection="row">
|
|
92
|
+
<Text color={tuiColors.textTertiary}> {idx === node.subtasks!.length - 1 ? '└──' : '├──'} </Text>
|
|
93
|
+
<AgentStateIcon state={subtask.state} tick={tick} />
|
|
94
|
+
<Text color={tuiColors.textTertiary}> {subtask.name}</Text>
|
|
95
|
+
</Box>
|
|
96
|
+
))}
|
|
97
|
+
</Box>
|
|
98
|
+
)}
|
|
60
99
|
</Box>
|
|
61
100
|
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
interface DAGLevelViewProps {
|
|
104
|
+
level: DAGLevel;
|
|
105
|
+
tick: number;
|
|
106
|
+
isActive: boolean;
|
|
62
107
|
}
|
|
63
108
|
|
|
64
|
-
function DAGLevelView({ level, tick, isActive }:
|
|
109
|
+
const DAGLevelView = memo(function DAGLevelView({ level, tick, isActive }: DAGLevelViewProps) {
|
|
110
|
+
const levelColor = isActive ? tuiColors.primary : tuiColors.textSecondary;
|
|
111
|
+
const statusColor = level.status === 'done'
|
|
112
|
+
? tuiColors.success
|
|
113
|
+
: level.status === 'running'
|
|
114
|
+
? tuiColors.warning
|
|
115
|
+
: tuiColors.textTertiary;
|
|
116
|
+
|
|
65
117
|
return (
|
|
66
118
|
<Box flexDirection="column" marginBottom={1}>
|
|
67
119
|
<Box flexDirection="row">
|
|
68
|
-
<Text color={
|
|
69
|
-
|
|
120
|
+
<Text color={levelColor} bold>{level.name.padEnd(12)}</Text>
|
|
121
|
+
<AnimatedProgressBar
|
|
122
|
+
progress={level.progress}
|
|
123
|
+
width={16}
|
|
124
|
+
tick={tick}
|
|
125
|
+
animated={isActive}
|
|
126
|
+
showMarker={isActive}
|
|
127
|
+
glowEffect={isActive}
|
|
128
|
+
/>
|
|
129
|
+
</Box>
|
|
130
|
+
<Box flexDirection="row">
|
|
131
|
+
<Text color={isActive ? tuiColors.primary : tuiColors.textTertiary}>
|
|
132
|
+
{isActive ? "┃" : "│"}
|
|
70
133
|
</Text>
|
|
71
|
-
<Text color="gray"> </Text>
|
|
72
|
-
<ProgressBar progress={level.progress} width={12} />
|
|
73
|
-
<Text color="gray"> {level.progress}%</Text>
|
|
74
134
|
</Box>
|
|
75
|
-
{level.nodes.map((node) => (
|
|
76
|
-
<DAGNodeItem
|
|
135
|
+
{level.nodes.map((node, idx) => (
|
|
136
|
+
<DAGNodeItem
|
|
137
|
+
key={node.id}
|
|
138
|
+
node={node}
|
|
139
|
+
tick={tick}
|
|
140
|
+
isLast={idx === level.nodes.length - 1}
|
|
141
|
+
/>
|
|
77
142
|
))}
|
|
78
143
|
</Box>
|
|
79
144
|
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
interface DAGPanelProps {
|
|
148
|
+
workflowState: WorkflowState;
|
|
149
|
+
tick: number;
|
|
150
|
+
isActive: boolean;
|
|
80
151
|
}
|
|
81
152
|
|
|
82
|
-
export function DAGPanel({ workflowState, tick, isActive }: DAGPanelProps) {
|
|
83
|
-
const borderColor = isActive ?
|
|
153
|
+
export const DAGPanel = memo(function DAGPanel({ workflowState, tick, isActive }: DAGPanelProps) {
|
|
154
|
+
const borderColor = isActive ? tuiColors.primary : tuiColors.border;
|
|
155
|
+
|
|
156
|
+
const levelViews = useMemo(() =>
|
|
157
|
+
workflowState.levels.map((level, index) => (
|
|
158
|
+
<DAGLevelView
|
|
159
|
+
key={level.name}
|
|
160
|
+
level={level}
|
|
161
|
+
tick={tick}
|
|
162
|
+
isActive={index === workflowState.currentLevel}
|
|
163
|
+
/>
|
|
164
|
+
)),
|
|
165
|
+
[workflowState.levels, workflowState.currentLevel, tick]
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const isAnimating = useMemo(() =>
|
|
169
|
+
workflowState.totalProgress > 0 && workflowState.totalProgress < 100,
|
|
170
|
+
[workflowState.totalProgress]
|
|
171
|
+
);
|
|
84
172
|
|
|
85
173
|
return (
|
|
86
174
|
<Box
|
|
87
175
|
flexDirection="column"
|
|
88
|
-
width={
|
|
176
|
+
width={46}
|
|
89
177
|
borderStyle="single"
|
|
90
178
|
borderColor={borderColor}
|
|
91
179
|
paddingX={1}
|
|
92
180
|
>
|
|
93
|
-
<Box
|
|
94
|
-
<Text color=
|
|
95
|
-
<Text color=
|
|
181
|
+
<Box marginBottom={1}>
|
|
182
|
+
<Text color={tuiColors.primary} bold>┌─</Text>
|
|
183
|
+
<Text color={tuiColors.primary} bold> DAG_EXECUTION </Text>
|
|
184
|
+
<Text color={tuiColors.textTertiary}>──────────────────────</Text>
|
|
96
185
|
</Box>
|
|
97
186
|
|
|
98
187
|
<Box flexDirection="column" flexGrow={1}>
|
|
99
|
-
{
|
|
100
|
-
<DAGLevelView
|
|
101
|
-
key={level.name}
|
|
102
|
-
level={level}
|
|
103
|
-
tick={tick}
|
|
104
|
-
isActive={index === workflowState.currentLevel}
|
|
105
|
-
/>
|
|
106
|
-
))}
|
|
188
|
+
{levelViews}
|
|
107
189
|
</Box>
|
|
108
190
|
|
|
109
|
-
<Box
|
|
110
|
-
<Text color=
|
|
111
|
-
|
|
112
|
-
|
|
191
|
+
<Box marginTop={1}>
|
|
192
|
+
<Text color={tuiColors.textTertiary}>├─ TOTAL ─────────────────────────</Text>
|
|
193
|
+
</Box>
|
|
194
|
+
<Box flexDirection="row">
|
|
195
|
+
<Text color={tuiColors.textSecondary}>Progress: </Text>
|
|
196
|
+
<AnimatedProgressBar
|
|
197
|
+
progress={workflowState.totalProgress}
|
|
198
|
+
width={16}
|
|
199
|
+
tick={tick}
|
|
200
|
+
animated={isAnimating}
|
|
201
|
+
showMarker
|
|
202
|
+
/>
|
|
113
203
|
</Box>
|
|
114
204
|
</Box>
|
|
115
205
|
);
|
|
116
|
-
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
export type { DAGNode, DAGLevel, WorkflowState, DAGSubtask };
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import React, { memo, useMemo } from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { tuiColors } from "../styles/index.js";
|
|
4
|
+
import { AnimatedBranch } from "./AnimatedBranch.js";
|
|
5
|
+
|
|
6
|
+
interface TimelineAgent {
|
|
7
|
+
name: string;
|
|
8
|
+
startTime: number;
|
|
9
|
+
endTime?: number;
|
|
10
|
+
isActive: boolean;
|
|
11
|
+
color?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface TimelineLevel {
|
|
15
|
+
name: string;
|
|
16
|
+
startTime: number;
|
|
17
|
+
endTime?: number;
|
|
18
|
+
progress: number;
|
|
19
|
+
status: 'done' | 'running' | 'pending';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ExecutionTimelineProps {
|
|
23
|
+
tick: number;
|
|
24
|
+
totalDuration: number;
|
|
25
|
+
currentTime: number;
|
|
26
|
+
levels: TimelineLevel[];
|
|
27
|
+
agents: TimelineAgent[];
|
|
28
|
+
isActive?: boolean;
|
|
29
|
+
width?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const ACTIVE_MARKER_FRAMES = ["┃", "║", "┃", "║"];
|
|
33
|
+
|
|
34
|
+
const BAR_COLORS: Record<string, string> = {
|
|
35
|
+
done: tuiColors.success,
|
|
36
|
+
running: tuiColors.warning,
|
|
37
|
+
pending: tuiColors.textTertiary,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const STATUS_TEXT = {
|
|
41
|
+
done: (endTime: number | undefined) => `done at ${endTime?.toFixed(1)}s`,
|
|
42
|
+
running: () => "running...",
|
|
43
|
+
pending: () => "pending",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function formatTime(s: number): string {
|
|
47
|
+
return `${s}s`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface TimelineBarProps {
|
|
51
|
+
level: TimelineLevel;
|
|
52
|
+
timeScale: number;
|
|
53
|
+
width: number;
|
|
54
|
+
currentTime: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const TimelineBar = memo(function TimelineBar({ level, timeScale, width, currentTime }: TimelineBarProps) {
|
|
58
|
+
const startCol = Math.floor(level.startTime * timeScale);
|
|
59
|
+
const endCol = level.endTime
|
|
60
|
+
? Math.floor(level.endTime * timeScale)
|
|
61
|
+
: Math.floor(currentTime * timeScale);
|
|
62
|
+
const barWidth = Math.max(0, endCol - startCol);
|
|
63
|
+
const beforeBar = "░".repeat(startCol);
|
|
64
|
+
|
|
65
|
+
const barChar = level.status === 'done' ? "█" : level.status === 'running' ? "▓" : "░";
|
|
66
|
+
const afterBar = "░".repeat(Math.max(0, width - endCol));
|
|
67
|
+
|
|
68
|
+
const statusText = STATUS_TEXT[level.status](level.endTime);
|
|
69
|
+
const paddedName = useMemo(() => level.name.padEnd(4), [level.name]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Box flexDirection="row">
|
|
73
|
+
<Text color={tuiColors.textTertiary}>{paddedName} </Text>
|
|
74
|
+
<Text color={BAR_COLORS[level.status]}>{beforeBar}{barChar.repeat(barWidth)}</Text>
|
|
75
|
+
<Text color={tuiColors.textTertiary}>{afterBar}</Text>
|
|
76
|
+
<Text color={tuiColors.textTertiary}> {statusText}</Text>
|
|
77
|
+
</Box>
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
interface AgentTimelineProps {
|
|
82
|
+
agent: TimelineAgent;
|
|
83
|
+
timeScale: number;
|
|
84
|
+
width: number;
|
|
85
|
+
currentTime: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const AgentTimeline = memo(function AgentTimeline({ agent, timeScale, width, currentTime }: AgentTimelineProps) {
|
|
89
|
+
const startCol = Math.floor(agent.startTime * timeScale);
|
|
90
|
+
const endCol = agent.endTime
|
|
91
|
+
? Math.floor(agent.endTime * timeScale)
|
|
92
|
+
: Math.floor(currentTime * timeScale);
|
|
93
|
+
const barWidth = Math.max(0, endCol - startCol);
|
|
94
|
+
const indent = " ".repeat(startCol);
|
|
95
|
+
const bar = agent.isActive ? "─".repeat(barWidth) + "▶" : "─".repeat(barWidth) + "┘";
|
|
96
|
+
const afterBar = " ".repeat(Math.max(0, width - endCol - 1));
|
|
97
|
+
|
|
98
|
+
const agentColor = agent.color || (agent.isActive ? tuiColors.primary : tuiColors.textSecondary);
|
|
99
|
+
const prefix = agent.isActive ? "▶" : "●";
|
|
100
|
+
const paddedName = useMemo(() => agent.name.padEnd(10), [agent.name]);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Box flexDirection="row">
|
|
104
|
+
<Text color={agentColor}>{prefix} {paddedName} </Text>
|
|
105
|
+
<Text color={tuiColors.textTertiary}>{indent}</Text>
|
|
106
|
+
<Text color={agentColor}>{bar}</Text>
|
|
107
|
+
<Text color={tuiColors.textTertiary}>{afterBar}</Text>
|
|
108
|
+
</Box>
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
export const ExecutionTimeline = memo(function ExecutionTimeline({
|
|
113
|
+
tick,
|
|
114
|
+
totalDuration,
|
|
115
|
+
currentTime,
|
|
116
|
+
levels,
|
|
117
|
+
agents,
|
|
118
|
+
isActive = false,
|
|
119
|
+
width = 50,
|
|
120
|
+
}: ExecutionTimelineProps) {
|
|
121
|
+
const borderColor = isActive ? tuiColors.primary : tuiColors.border;
|
|
122
|
+
const timeScale = width / totalDuration;
|
|
123
|
+
const markerPositions = [0, 5, 10, 15, 20];
|
|
124
|
+
|
|
125
|
+
const activeMarker = isActive ? ACTIVE_MARKER_FRAMES[tick % ACTIVE_MARKER_FRAMES.length] : "│";
|
|
126
|
+
|
|
127
|
+
const markerElements = useMemo(() =>
|
|
128
|
+
markerPositions.map((pos, idx) => (
|
|
129
|
+
<Box key={idx} width={10}>
|
|
130
|
+
<Text color={tuiColors.textTertiary}>{formatTime(pos).padStart(6)}</Text>
|
|
131
|
+
</Box>
|
|
132
|
+
)),
|
|
133
|
+
[]
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const separatorElements = useMemo(() =>
|
|
137
|
+
Array.from({ length: 5 }).map((_, idx) => (
|
|
138
|
+
<Box key={idx} width={10}>
|
|
139
|
+
<Text color={tuiColors.textTertiary}>{idx === 0 ? "│" : " │"}</Text>
|
|
140
|
+
</Box>
|
|
141
|
+
)),
|
|
142
|
+
[]
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const levelElements = useMemo(() =>
|
|
146
|
+
levels.map((level, idx) => (
|
|
147
|
+
<Box key={idx} marginBottom={1}>
|
|
148
|
+
<TimelineBar level={level} timeScale={timeScale} width={width} currentTime={currentTime} />
|
|
149
|
+
</Box>
|
|
150
|
+
)),
|
|
151
|
+
[levels, timeScale, width, currentTime]
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const agentElements = useMemo(() =>
|
|
155
|
+
agents.map((agent, idx) => (
|
|
156
|
+
<Box key={idx}>
|
|
157
|
+
<AgentTimeline agent={agent} timeScale={timeScale} width={width} currentTime={currentTime} />
|
|
158
|
+
</Box>
|
|
159
|
+
)),
|
|
160
|
+
[agents, timeScale, width, currentTime]
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Box flexDirection="column" borderStyle="single" borderColor={borderColor} paddingX={1}>
|
|
165
|
+
<Box marginBottom={1}>
|
|
166
|
+
<Text color={tuiColors.primary} bold>┌─</Text>
|
|
167
|
+
<Text color={tuiColors.primary} bold> EXECUTION_TIMELINE </Text>
|
|
168
|
+
<Text color={tuiColors.textTertiary}>────────────────</Text>
|
|
169
|
+
</Box>
|
|
170
|
+
|
|
171
|
+
<Box flexDirection="row" marginBottom={1}>
|
|
172
|
+
{markerElements}
|
|
173
|
+
</Box>
|
|
174
|
+
|
|
175
|
+
<Box flexDirection="row" marginBottom={1}>
|
|
176
|
+
{separatorElements}
|
|
177
|
+
</Box>
|
|
178
|
+
|
|
179
|
+
<Box flexDirection="row" marginBottom={1}>
|
|
180
|
+
<Text color={tuiColors.textTertiary}>{"├" + "─".repeat(width - 2) + "┤"}</Text>
|
|
181
|
+
</Box>
|
|
182
|
+
|
|
183
|
+
<Box flexDirection="column">
|
|
184
|
+
{levelElements}
|
|
185
|
+
</Box>
|
|
186
|
+
|
|
187
|
+
<Box flexDirection="row" marginTop={1} marginBottom={1}>
|
|
188
|
+
<AnimatedBranch type="vertical" tick={tick} animated={isActive} />
|
|
189
|
+
</Box>
|
|
190
|
+
|
|
191
|
+
<Box marginTop={1}>
|
|
192
|
+
<Text color={tuiColors.textSecondary}>Agents:</Text>
|
|
193
|
+
</Box>
|
|
194
|
+
|
|
195
|
+
<Box flexDirection="column" marginTop={1}>
|
|
196
|
+
{agentElements}
|
|
197
|
+
</Box>
|
|
198
|
+
</Box>
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
interface MiniTimelineProps {
|
|
203
|
+
progress: number;
|
|
204
|
+
tick: number;
|
|
205
|
+
isActive: boolean;
|
|
206
|
+
width?: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export const MiniTimeline = memo(function MiniTimeline({ progress, tick, isActive, width = 30 }: MiniTimelineProps) {
|
|
210
|
+
const filled = Math.floor((progress / 100) * width);
|
|
211
|
+
const empty = width - filled;
|
|
212
|
+
const currentPos = Math.min(filled, width - 1);
|
|
213
|
+
|
|
214
|
+
const before = "─".repeat(currentPos);
|
|
215
|
+
const marker = isActive ? "●" : "○";
|
|
216
|
+
const after = "─".repeat(empty);
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<Box flexDirection="row">
|
|
220
|
+
<Text color={tuiColors.textTertiary}>├{before}</Text>
|
|
221
|
+
<Text color={isActive ? tuiColors.primary : tuiColors.textSecondary}>{marker}</Text>
|
|
222
|
+
<Text color={tuiColors.textTertiary}>{after}┤</Text>
|
|
223
|
+
</Box>
|
|
224
|
+
);
|
|
225
|
+
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { memo, useMemo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
+
import { tuiColors, getStatusIndicator, getProviderTag } from "../styles/index.js";
|
|
4
|
+
import { StatusPulse } from "./animations/index.js";
|
|
3
5
|
|
|
4
6
|
interface HeaderProps {
|
|
5
7
|
projectName: string;
|
|
@@ -10,67 +12,98 @@ interface HeaderProps {
|
|
|
10
12
|
activePanel: string;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
const
|
|
14
|
-
const panelNames: Record<string, string> = {
|
|
15
|
+
const PANEL_NAMES: Record<string, string> = {
|
|
15
16
|
chat: "CHAT",
|
|
16
17
|
dag: "DAG",
|
|
17
18
|
status: "STATUS",
|
|
19
|
+
logs: "LOGS",
|
|
20
|
+
metrics: "METRICS",
|
|
21
|
+
memory: "MEMORY",
|
|
18
22
|
};
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
const statusColors = {
|
|
22
|
-
ready: "green",
|
|
23
|
-
running: "yellow",
|
|
24
|
-
error: "red",
|
|
25
|
-
};
|
|
24
|
+
const PANELS = ["chat", "dag", "logs", "metrics", "memory"] as const;
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
export const Header = memo(function Header({
|
|
27
|
+
projectName,
|
|
28
|
+
agentCount,
|
|
29
|
+
provider,
|
|
30
|
+
status,
|
|
31
|
+
tick,
|
|
32
|
+
activePanel
|
|
33
|
+
}: HeaderProps) {
|
|
34
|
+
const statusInfo = useMemo(() => getStatusIndicator(status), [status]);
|
|
35
|
+
const providerInfo = useMemo(() => getProviderTag(provider), [provider]);
|
|
32
36
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const statusText = status === "ready" ? "ONLINE" : status === "running" ? "RUNNING" : "ERROR";
|
|
38
|
+
const statusColor = status === "ready"
|
|
39
|
+
? tuiColors.success
|
|
40
|
+
: status === "running"
|
|
41
|
+
? tuiColors.warning
|
|
42
|
+
: tuiColors.error;
|
|
43
|
+
|
|
44
|
+
const pulseStatus = status === "ready"
|
|
45
|
+
? "online"
|
|
46
|
+
: status === "running"
|
|
47
|
+
? "running"
|
|
48
|
+
: "error";
|
|
49
|
+
|
|
50
|
+
const panelElements = useMemo(() =>
|
|
51
|
+
PANELS.map((panel) => (
|
|
52
|
+
<Box key={panel} marginRight={1}>
|
|
53
|
+
<Text
|
|
54
|
+
color={activePanel === panel ? tuiColors.primary : tuiColors.textTertiary}
|
|
55
|
+
bold={activePanel === panel}
|
|
56
|
+
>
|
|
57
|
+
[{PANEL_NAMES[panel]}]
|
|
58
|
+
</Text>
|
|
59
|
+
</Box>
|
|
60
|
+
)),
|
|
61
|
+
[activePanel]
|
|
62
|
+
);
|
|
36
63
|
|
|
37
64
|
return (
|
|
38
|
-
<Box
|
|
39
|
-
flexDirection="column"
|
|
40
|
-
borderStyle="single"
|
|
41
|
-
borderColor="gray"
|
|
42
|
-
width="100%"
|
|
43
|
-
>
|
|
65
|
+
<Box flexDirection="column" width="100%">
|
|
44
66
|
<Box
|
|
45
67
|
flexDirection="row"
|
|
46
68
|
justifyContent="space-between"
|
|
47
69
|
alignItems="center"
|
|
48
70
|
paddingX={1}
|
|
71
|
+
borderStyle="single"
|
|
72
|
+
borderColor={tuiColors.border}
|
|
49
73
|
>
|
|
50
74
|
<Box flexDirection="row" alignItems="center">
|
|
51
|
-
<Text color=
|
|
52
|
-
<Text color=
|
|
53
|
-
<Text color=
|
|
75
|
+
<Text color={tuiColors.primary} bold>■</Text>
|
|
76
|
+
<Text color={tuiColors.textPrimary} bold> RAX-FLOW</Text>
|
|
77
|
+
<Text color={tuiColors.textSecondary}> HUB</Text>
|
|
54
78
|
</Box>
|
|
55
|
-
<Box flexDirection="row" alignItems="center">
|
|
56
|
-
<Text color=
|
|
57
|
-
<Text color=
|
|
58
|
-
<Text color=
|
|
59
|
-
<Text color=
|
|
60
|
-
<Text color=
|
|
61
|
-
<Text color={
|
|
79
|
+
<Box flexDirection="row" alignItems="center" gap={1}>
|
|
80
|
+
<Text color={tuiColors.textTertiary}>Project:</Text>
|
|
81
|
+
<Text color={tuiColors.textPrimary}> {projectName}</Text>
|
|
82
|
+
<Text color={tuiColors.textQuaternary}> │</Text>
|
|
83
|
+
<Text color={tuiColors.textTertiary}> Agents:</Text>
|
|
84
|
+
<Text color={tuiColors.success}> {agentCount}/12</Text>
|
|
85
|
+
<Text color={tuiColors.textQuaternary}> │</Text>
|
|
86
|
+
<Text color={tuiColors.textSecondary}>{providerInfo.code}</Text>
|
|
87
|
+
<Text color={statusColor}> </Text>
|
|
88
|
+
<StatusPulse status={pulseStatus} tick={tick} />
|
|
89
|
+
<Text color={statusColor}> {statusText}</Text>
|
|
62
90
|
</Box>
|
|
63
91
|
</Box>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<
|
|
92
|
+
|
|
93
|
+
<Box borderStyle="single" borderColor={tuiColors.primary} paddingX={1}>
|
|
94
|
+
<Text color={tuiColors.textTertiary} italic>
|
|
95
|
+
Orchestrator that Evolves with Your Host Tools
|
|
96
|
+
</Text>
|
|
97
|
+
</Box>
|
|
98
|
+
|
|
99
|
+
<Box flexDirection="row" paddingX={1} justifyContent="space-between">
|
|
100
|
+
<Box flexDirection="row">
|
|
101
|
+
{panelElements}
|
|
102
|
+
</Box>
|
|
103
|
+
<Box flexDirection="row">
|
|
104
|
+
<Text color={tuiColors.textQuaternary}>Tab:Switch │ ←:View │ ?:Help │ Ctrl+C:Quit</Text>
|
|
105
|
+
</Box>
|
|
73
106
|
</Box>
|
|
74
107
|
</Box>
|
|
75
108
|
);
|
|
76
|
-
}
|
|
109
|
+
});
|