@taui-standard/ink-adapter 1.0.6 → 1.0.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/README.md +13 -2
- package/dist/renderer.d.ts +1 -0
- package/dist/renderer.js +40 -6
- package/examples/basic-htop/Screenshot_Example_Dashboard.png +0 -0
- package/examples/basic-htop/Screenshot_Example_Htop.png +0 -0
- package/examples/basic-htop/index.ts +74 -51
- package/examples/interactive-dashboard/index.ts +111 -47
- package/examples/interactive-dashboard/package-lock.json +46 -0
- package/examples/interactive-dashboard/package.json +4 -0
- package/package.json +1 -1
- package/src/renderer.tsx +62 -11
- package/examples/basic-htop/Screenshot.png +0 -0
package/README.md
CHANGED
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
The official [Ink](https://github.com/vadimdemedes/ink) adapter for **Terminal Agent UI (TAUI)**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Ecosystem
|
|
6
|
+
Built on the **[TAUI-0001 Specification](https://github.com/TAUI-Standards/taui-standards)** and powered by:
|
|
7
|
+
- **[@taui-standard/core](https://github.com/TAUI-Standards/taui-core)**: Core runtime and state management.
|
|
8
|
+
- **[@taui-standard/validator](https://github.com/TAUI-Standards/taui-validator)**: Schema and primitive validation.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
*All packages and the TAUI specification created by **Tariq Shams***.
|
|
11
|
+
|
|
12
|
+
## Demos
|
|
13
|
+
|
|
14
|
+
### High-Fidelity HTOP
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
### Interactive Dashboard
|
|
18
|
+

|
|
8
19
|
|
|
9
20
|
## Features
|
|
10
21
|
- **Spec-Compliant**: Renders all primitives from TAUI-0001.
|
package/dist/renderer.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare const TAUIText: React.FC<RendererProps>;
|
|
|
9
9
|
export declare const TAUIBox: React.FC<RendererProps>;
|
|
10
10
|
export declare const TAUIButton: React.FC<RendererProps>;
|
|
11
11
|
export declare const TAUIInput: React.FC<RendererProps>;
|
|
12
|
+
export declare const TAUISelect: React.FC<RendererProps>;
|
|
12
13
|
export declare const TAUIProgress: React.FC<RendererProps>;
|
|
13
14
|
export declare const TAUIKeyBinding: React.FC<RendererProps>;
|
|
14
15
|
export declare const TAUITable: React.FC<RendererProps>;
|
package/dist/renderer.js
CHANGED
|
@@ -21,7 +21,7 @@ export const TAUIBox = ({ node, runtime }) => {
|
|
|
21
21
|
if (borderStyle && !validStyles.includes(borderStyle)) {
|
|
22
22
|
borderStyle = 'single';
|
|
23
23
|
}
|
|
24
|
-
return (_jsxs(Box, { flexDirection: flexDirection, padding: typeof node.padding === 'number' ? node.padding : undefined, gap: node.gap, borderStyle: borderStyle, children: [node.type === 'Panel' && node.title && (_jsx(Box, { position: "absolute", marginTop: -1, marginLeft: 1, paddingX: 1, children: _jsx(Text, { bold: true, children: node.title }) })), node.children?.map((child, idx) => (_jsx(TAUIRenderer, { node: child, runtime: runtime }, child.id || `${node.type}-${idx}`)))] }));
|
|
24
|
+
return (_jsxs(Box, { flexDirection: flexDirection, padding: typeof node.padding === 'number' ? node.padding : undefined, gap: node.gap, borderStyle: borderStyle, children: [node.type === 'Panel' && node.title && (_jsx(Box, { position: "absolute", marginTop: -1, marginLeft: 1, paddingX: 1, children: _jsx(Text, { bold: true, color: node.style?.color, children: node.title }) })), node.children?.map((child, idx) => (_jsx(TAUIRenderer, { node: child, runtime: runtime }, child.id || `${node.type}-${idx}`)))] }));
|
|
25
25
|
};
|
|
26
26
|
export const TAUIButton = ({ node, runtime }) => {
|
|
27
27
|
const { isFocused } = useFocus({ id: node.id });
|
|
@@ -34,7 +34,7 @@ export const TAUIButton = ({ node, runtime }) => {
|
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: isFocused ? '
|
|
37
|
+
return (_jsx(Box, { borderStyle: "round", borderColor: isFocused ? (node.style?.color || 'white') : (node.style?.color || 'gray'), paddingX: 1, children: _jsx(Text, { color: node.style?.color, bold: isFocused, children: node.label }) }));
|
|
38
38
|
};
|
|
39
39
|
export const TAUIInput = ({ node, runtime }) => {
|
|
40
40
|
const { isFocused } = useFocus({ id: node.id });
|
|
@@ -46,14 +46,46 @@ export const TAUIInput = ({ node, runtime }) => {
|
|
|
46
46
|
timestamp: new Date().toISOString()
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
|
-
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [node.placeholder && _jsxs(Text, { dimColor: true, children: [node.placeholder, ": "] }), _jsx(Box, { borderStyle: "single", borderColor: isFocused ? '
|
|
49
|
+
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [node.placeholder && _jsxs(Text, { dimColor: true, children: [node.placeholder, ": "] }), _jsx(Box, { borderStyle: "single", borderColor: isFocused ? (node.style?.color || 'white') : (node.style?.color || 'gray'), paddingX: 1, minWidth: 10, children: isFocused ? (_jsx(TextInput, { value: node.value || '', onChange: onChange, mask: node.mask ? '*' : undefined })) : (_jsx(Text, { color: node.style?.color, children: node.mask ? '*'.repeat((node.value || '').length) : (node.value || ' ') })) })] }));
|
|
50
|
+
};
|
|
51
|
+
export const TAUISelect = ({ node, runtime }) => {
|
|
52
|
+
const { isFocused } = useFocus({ id: node.id });
|
|
53
|
+
const options = node.options || [];
|
|
54
|
+
const currentValue = node.value;
|
|
55
|
+
const currentIndex = options.findIndex((opt) => opt.value === currentValue);
|
|
56
|
+
useInput((input, key) => {
|
|
57
|
+
if (isFocused) {
|
|
58
|
+
if (key.upArrow || key.leftArrow) {
|
|
59
|
+
const nextIndex = (currentIndex - 1 + options.length) % options.length;
|
|
60
|
+
runtime.dispatchRawEvent({
|
|
61
|
+
type: 'change',
|
|
62
|
+
targetId: node.id,
|
|
63
|
+
payload: { value: options[nextIndex].value },
|
|
64
|
+
timestamp: new Date().toISOString()
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
else if (key.downArrow || key.rightArrow) {
|
|
68
|
+
const nextIndex = (currentIndex + 1) % options.length;
|
|
69
|
+
runtime.dispatchRawEvent({
|
|
70
|
+
type: 'change',
|
|
71
|
+
targetId: node.id,
|
|
72
|
+
payload: { value: options[nextIndex].value },
|
|
73
|
+
timestamp: new Date().toISOString()
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return (_jsx(Box, { flexDirection: "row", gap: 1, children: options.map((opt, i) => {
|
|
79
|
+
const isSelected = opt.value === currentValue;
|
|
80
|
+
return (_jsx(Box, { borderStyle: "single", borderColor: isFocused && isSelected ? (node.style?.color || 'white') : 'gray', paddingX: 1, children: _jsxs(Text, { color: node.style?.color, bold: isSelected, children: [isSelected ? '> ' : '', opt.label] }) }, i));
|
|
81
|
+
}) }));
|
|
50
82
|
};
|
|
51
83
|
export const TAUIProgress = ({ node }) => {
|
|
52
84
|
const width = 20;
|
|
53
85
|
const val = node.value || 0;
|
|
54
86
|
const completed = Math.round(val * width);
|
|
55
87
|
const bar = '\u2588'.repeat(completed) + '\u2591'.repeat(width - completed);
|
|
56
|
-
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [node.label && _jsx(Text, { children: node.label }), _jsx(Text, { color:
|
|
88
|
+
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [node.label && _jsx(Text, { color: node.style?.color, children: node.label }), _jsx(Text, { color: node.style?.color, children: bar }), _jsxs(Text, { color: node.style?.color, children: [Math.round(val * 100), "%"] })] }));
|
|
57
89
|
};
|
|
58
90
|
export const TAUIKeyBinding = ({ node, runtime }) => {
|
|
59
91
|
if (node.type !== 'KeyBinding')
|
|
@@ -87,13 +119,13 @@ export const TAUITable = ({ node }) => {
|
|
|
87
119
|
return null;
|
|
88
120
|
const headers = node.headers || [];
|
|
89
121
|
const rows = node.rows || [];
|
|
90
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [_jsx(Box, { flexDirection: "row", borderStyle: "single", borderBottom: true, children: headers.map((h, i) => (_jsx(Box, { flexGrow: 1, minWidth: 10, children: _jsx(Text, { bold: true, color:
|
|
122
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: [_jsx(Box, { flexDirection: "row", borderStyle: "single", borderBottom: true, children: headers.map((h, i) => (_jsx(Box, { flexGrow: 1, minWidth: 10, children: _jsx(Text, { bold: true, color: node.style?.color, children: h }) }, i))) }), rows.map((row, i) => (_jsx(Box, { flexDirection: "row", children: row.map((cell, j) => (_jsx(Box, { flexGrow: 1, minWidth: 10, children: _jsx(Text, { color: node.style?.color, children: cell }) }, j))) }, i)))] }));
|
|
91
123
|
};
|
|
92
124
|
export const TAUILog = ({ node }) => {
|
|
93
125
|
if (node.type !== 'Log')
|
|
94
126
|
return null;
|
|
95
127
|
const lines = node.lines || [];
|
|
96
|
-
return (_jsx(Box, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: lines.slice(-(node.maxLines || 100)).map((line, i) => (_jsx(Text, { children: line }, i))) }));
|
|
128
|
+
return (_jsx(Box, { flexDirection: "column", borderStyle: "single", paddingX: 1, children: lines.slice(-(node.maxLines || 100)).map((line, i) => (_jsx(Text, { color: node.style?.color, children: line }, i))) }));
|
|
97
129
|
};
|
|
98
130
|
export const TAUIRenderer = (props) => {
|
|
99
131
|
const { node } = props;
|
|
@@ -110,6 +142,8 @@ export const TAUIRenderer = (props) => {
|
|
|
110
142
|
return _jsx(TAUIButton, { ...props });
|
|
111
143
|
case 'Input':
|
|
112
144
|
return _jsx(TAUIInput, { ...props });
|
|
145
|
+
case 'Select':
|
|
146
|
+
return _jsx(TAUISelect, { ...props });
|
|
113
147
|
case 'Progress':
|
|
114
148
|
return _jsx(TAUIProgress, { ...props });
|
|
115
149
|
case 'Table':
|
|
Binary file
|
|
Binary file
|
|
@@ -11,7 +11,7 @@ function getHtopData() {
|
|
|
11
11
|
const loadAvg = os.loadavg();
|
|
12
12
|
const cpus = os.cpus();
|
|
13
13
|
|
|
14
|
-
// Mock process list
|
|
14
|
+
// Mock process list
|
|
15
15
|
const mockProcesses = [
|
|
16
16
|
["1234", "root", loadAvg[0].toFixed(1), "1.2", "systemd"],
|
|
17
17
|
["5678", "user", (loadAvg[1] / 2).toFixed(1), "0.5", "bash"],
|
|
@@ -23,70 +23,98 @@ function getHtopData() {
|
|
|
23
23
|
const doc: any = {
|
|
24
24
|
version: "1.0",
|
|
25
25
|
metadata: {
|
|
26
|
-
title: "TAUI
|
|
26
|
+
title: "TAUI Official Dashboard",
|
|
27
27
|
author: "Tariq Shams"
|
|
28
28
|
},
|
|
29
29
|
screen: {
|
|
30
|
-
type: "
|
|
30
|
+
type: "Column",
|
|
31
31
|
style: { backgroundColor: "black", color: "#FF8C00" },
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
padding: 1,
|
|
33
|
+
gap: 1,
|
|
34
34
|
children: [
|
|
35
35
|
{
|
|
36
|
-
id: "
|
|
36
|
+
id: "header_panel",
|
|
37
37
|
type: "Panel",
|
|
38
|
-
title: "
|
|
39
|
-
borderStyle: "
|
|
38
|
+
title: "TAUI Ecosystem Info",
|
|
39
|
+
borderStyle: "single",
|
|
40
40
|
style: { color: "#FF8C00" },
|
|
41
41
|
children: [
|
|
42
42
|
{
|
|
43
|
-
type: "
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
type: "Box",
|
|
44
|
+
flexDirection: "column",
|
|
45
|
+
gap: 0,
|
|
46
|
+
children: [
|
|
47
|
+
{ type: "Text", content: 'Official "@taui-standard/ink-adapter" fully compliant with TAUI 0001', style: { bold: true, color: "#FF8C00" } },
|
|
48
|
+
{ type: "Text", content: "@taui-standard/core: Unified state and event runtime.", style: { color: "#FF8C00" } },
|
|
49
|
+
{ type: "Text", content: "@taui-standard/validator: Strict schema and data validation.", style: { color: "#FF8C00" } },
|
|
50
|
+
{ type: "Text", content: "All packages and the TAUI specification created by Tariq Shams", style: { italic: true, color: "#FF8C00" } }
|
|
51
|
+
]
|
|
52
52
|
}
|
|
53
53
|
]
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
style: { color: "#FF8C00" },
|
|
56
|
+
type: "Grid",
|
|
57
|
+
rows: ["12", "1fr", "3"],
|
|
58
|
+
columns: ["1fr", "1fr"],
|
|
59
|
+
gap: 1,
|
|
61
60
|
children: [
|
|
62
61
|
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
id: "cpu_panel",
|
|
63
|
+
type: "Panel",
|
|
64
|
+
title: "CPU Load",
|
|
65
|
+
borderStyle: "rounded",
|
|
66
|
+
style: { color: "#FF8C00" },
|
|
67
|
+
children: [
|
|
68
|
+
{
|
|
69
|
+
type: "Progress",
|
|
70
|
+
value: Math.min(loadAvg[0] / cpus.length, 1),
|
|
71
|
+
label: `Load 1m: ${(loadAvg[0]).toFixed(2)}`,
|
|
72
|
+
style: { color: "#FF8C00" }
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: "Text",
|
|
76
|
+
content: `Arch: ${os.arch()} | CPUs: ${cpus.length}`,
|
|
77
|
+
style: { color: "#FF8C00" }
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "mem_panel",
|
|
83
|
+
type: "Panel",
|
|
84
|
+
title: "Memory",
|
|
85
|
+
borderStyle: "rounded",
|
|
86
|
+
style: { color: "#FF8C00" },
|
|
87
|
+
children: [
|
|
88
|
+
{
|
|
89
|
+
type: "Progress",
|
|
90
|
+
value: usedMem / totalMem,
|
|
91
|
+
label: `MEM ${(usedMem / 1024 / 1024 / 1024).toFixed(1)}G / ${(totalMem / 1024 / 1024 / 1024).toFixed(1)}G`,
|
|
92
|
+
style: { color: "#FF8C00" }
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: "Text",
|
|
96
|
+
content: `Free: ${(freeMem / 1024 / 1024 / 1024).toFixed(1)}G`,
|
|
97
|
+
style: { color: "#FF8C00" }
|
|
98
|
+
}
|
|
99
|
+
]
|
|
67
100
|
},
|
|
68
101
|
{
|
|
69
|
-
|
|
70
|
-
|
|
102
|
+
id: "process_table",
|
|
103
|
+
type: "Table",
|
|
104
|
+
headers: ["PID", "USER", "CPU%", "MEM%", "COMMAND"],
|
|
105
|
+
rows: mockProcesses,
|
|
71
106
|
style: { color: "#FF8C00" }
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: "footer",
|
|
110
|
+
type: "Row",
|
|
111
|
+
children: [
|
|
112
|
+
{ type: "Text", content: " [Q: Quit] [Tab: Navigate] [Enter: Action] ", style: { color: "#FF8C00", bold: true } },
|
|
113
|
+
{ id: "refresh_btn", type: "Button", label: "Refresh Now", style: { color: "#FF8C00" } },
|
|
114
|
+
{ id: "quit_kb", type: "KeyBinding", key: "q", shift: true, action: "quit" }
|
|
115
|
+
]
|
|
72
116
|
}
|
|
73
117
|
]
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
id: "process_table",
|
|
77
|
-
type: "Table",
|
|
78
|
-
headers: ["PID", "USER", "CPU%", "MEM%", "COMMAND"],
|
|
79
|
-
rows: mockProcesses,
|
|
80
|
-
style: { color: "#FF8C00" }
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
id: "footer",
|
|
84
|
-
type: "Row",
|
|
85
|
-
children: [
|
|
86
|
-
{ type: "Text", content: " [q: Quit] [Tab: Navigate] [Enter: Action] ", style: { color: "#FF8C00", bold: true } },
|
|
87
|
-
{ id: "refresh_btn", type: "Button", label: "Refresh Now" },
|
|
88
|
-
{ id: "quit_kb", type: "KeyBinding", key: "q", action: "quit" }
|
|
89
|
-
]
|
|
90
118
|
}
|
|
91
119
|
]
|
|
92
120
|
}
|
|
@@ -94,21 +122,16 @@ function getHtopData() {
|
|
|
94
122
|
return doc;
|
|
95
123
|
}
|
|
96
124
|
|
|
97
|
-
// Initial set
|
|
98
125
|
runtime.setDocument(getHtopData());
|
|
99
126
|
|
|
100
|
-
// Update loop (every 2 seconds)
|
|
101
127
|
const interval = setInterval(() => {
|
|
102
128
|
try {
|
|
103
129
|
runtime.setDocument(getHtopData());
|
|
104
|
-
} catch (e) {
|
|
105
|
-
// Suppress errors during shutdown
|
|
106
|
-
}
|
|
130
|
+
} catch (e) {}
|
|
107
131
|
}, 2000);
|
|
108
132
|
|
|
109
|
-
// Handle interaction
|
|
110
133
|
runtime.onEvent((event) => {
|
|
111
|
-
if (event.type === 'key' &&
|
|
134
|
+
if (event.type === 'key' && event.payload?.key === 'q' && event.payload?.shift) {
|
|
112
135
|
clearInterval(interval);
|
|
113
136
|
process.exit(0);
|
|
114
137
|
}
|
|
@@ -8,82 +8,146 @@ let userEmail = '';
|
|
|
8
8
|
let selectedPriority = 'medium';
|
|
9
9
|
let logs: string[] = ['System initialized. Press "q" to exit.'];
|
|
10
10
|
|
|
11
|
-
function
|
|
12
|
-
|
|
11
|
+
function getDashboardData() {
|
|
12
|
+
const doc: any = {
|
|
13
13
|
version: "1.0",
|
|
14
|
-
metadata: {
|
|
14
|
+
metadata: {
|
|
15
|
+
title: "TAUI Official Interactive Demo",
|
|
16
|
+
author: "Tariq Shams"
|
|
17
|
+
},
|
|
15
18
|
screen: {
|
|
16
|
-
type: "
|
|
17
|
-
|
|
19
|
+
type: "Column",
|
|
20
|
+
style: { backgroundColor: "black", color: "#FF8C00" },
|
|
18
21
|
padding: 1,
|
|
22
|
+
gap: 1,
|
|
19
23
|
children: [
|
|
20
24
|
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{
|
|
27
|
-
type: "Column",
|
|
28
|
-
gap: 1,
|
|
25
|
+
id: "header_panel",
|
|
26
|
+
type: "Panel",
|
|
27
|
+
title: "TAUI Ecosystem Info",
|
|
28
|
+
borderStyle: "single",
|
|
29
|
+
style: { color: "#FF8C00" },
|
|
29
30
|
children: [
|
|
30
31
|
{
|
|
31
|
-
type: "
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
value: selectedPriority,
|
|
40
|
-
options: [
|
|
41
|
-
{ label: "Low Priority", value: "low" },
|
|
42
|
-
{ label: "Medium Priority", value: "medium" },
|
|
43
|
-
{ label: "High Priority", value: "high" }
|
|
32
|
+
type: "Box",
|
|
33
|
+
flexDirection: "column",
|
|
34
|
+
gap: 0,
|
|
35
|
+
children: [
|
|
36
|
+
{ type: "Text", content: 'Official "@taui-standard/ink-adapter" fully compliant with TAUI 0001', style: { bold: true, color: "#FF8C00" } },
|
|
37
|
+
{ type: "Text", content: "@taui-standard/core: Unified state and event runtime.", style: { color: "#FF8C00" } },
|
|
38
|
+
{ type: "Text", content: "@taui-standard/validator: Strict schema and data validation.", style: { color: "#FF8C00" } },
|
|
39
|
+
{ type: "Text", content: "All packages and the TAUI specification created by Tariq Shams", style: { italic: true, color: "#FF8C00" } }
|
|
44
40
|
]
|
|
45
|
-
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: "Panel",
|
|
46
|
+
title: "Interactive controls",
|
|
47
|
+
borderStyle: "rounded",
|
|
48
|
+
style: { color: "#FF8C00" },
|
|
49
|
+
children: [
|
|
46
50
|
{
|
|
47
|
-
type: "
|
|
48
|
-
gap:
|
|
51
|
+
type: "Column",
|
|
52
|
+
gap: 1,
|
|
49
53
|
children: [
|
|
50
|
-
{
|
|
51
|
-
|
|
54
|
+
{
|
|
55
|
+
id: "exit-key",
|
|
56
|
+
type: "KeyBinding",
|
|
57
|
+
key: "q",
|
|
58
|
+
shift: true,
|
|
59
|
+
action: "exit"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "email-input",
|
|
63
|
+
type: "Input",
|
|
64
|
+
placeholder: "Enter Target Email",
|
|
65
|
+
value: userEmail,
|
|
66
|
+
style: { color: "#FF8C00" }
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: "Text",
|
|
70
|
+
content: "Select Priority Level:",
|
|
71
|
+
style: { color: "#FF8C00" }
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "priority-select",
|
|
75
|
+
type: "Select",
|
|
76
|
+
value: selectedPriority,
|
|
77
|
+
style: { color: "#FF8C00" },
|
|
78
|
+
options: [
|
|
79
|
+
{ label: "Low Priority", value: "low" },
|
|
80
|
+
{ label: "Medium Priority", value: "medium" },
|
|
81
|
+
{ label: "High Priority", value: "high" }
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
type: "Row",
|
|
86
|
+
gap: 2,
|
|
87
|
+
children: [
|
|
88
|
+
{ id: "submit-btn", type: "Button", label: "Deploy Agent", style: { color: "#FF8C00" } },
|
|
89
|
+
{ id: "clear-btn", type: "Button", label: "Clear Logs", style: { color: "#FF8C00" } }
|
|
90
|
+
]
|
|
91
|
+
}
|
|
52
92
|
]
|
|
53
|
-
}
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: "Panel",
|
|
98
|
+
title: "Activity Stream",
|
|
99
|
+
borderStyle: "single",
|
|
100
|
+
style: { color: "#FF8C00" },
|
|
101
|
+
children: [
|
|
54
102
|
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
content: `> ${msg}`,
|
|
61
|
-
style: { dim: true }
|
|
62
|
-
}))
|
|
103
|
+
id: "activity-log",
|
|
104
|
+
type: "Log",
|
|
105
|
+
maxLines: 6,
|
|
106
|
+
lines: logs,
|
|
107
|
+
style: { color: "#FF8C00" }
|
|
63
108
|
}
|
|
64
109
|
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
type: "Text",
|
|
113
|
+
content: " [Tab/Shift+Tab] Navigate | [Enter] Select/Action | [Q] Quit ",
|
|
114
|
+
style: { color: "#FF8C00", dim: true }
|
|
65
115
|
}
|
|
66
116
|
]
|
|
67
117
|
}
|
|
68
|
-
}
|
|
118
|
+
};
|
|
119
|
+
return doc;
|
|
69
120
|
}
|
|
70
121
|
|
|
71
122
|
runtime.onEvent((event) => {
|
|
123
|
+
let changed = false;
|
|
124
|
+
|
|
72
125
|
if (event.type === 'change' && event.targetId === 'email-input') {
|
|
73
126
|
userEmail = (event.payload as any).value;
|
|
74
|
-
|
|
127
|
+
changed = true;
|
|
75
128
|
} else if (event.type === 'change' && event.targetId === 'priority-select') {
|
|
76
129
|
selectedPriority = (event.payload as any).value;
|
|
77
|
-
logs.push(`Priority set to: ${selectedPriority}`);
|
|
130
|
+
logs.push(`Priority set to: ${selectedPriority.toUpperCase()}`);
|
|
131
|
+
changed = true;
|
|
78
132
|
} else if (event.type === 'action' && event.targetId === 'submit-btn') {
|
|
79
|
-
|
|
133
|
+
if (!userEmail) {
|
|
134
|
+
logs.push("Error: Email is required.");
|
|
135
|
+
} else {
|
|
136
|
+
logs.push(`DEPLOYING agent to ${userEmail} [PRIORITY: ${selectedPriority.toUpperCase()}]`);
|
|
137
|
+
logs.push("Deployment status: IN_PROGRESS...");
|
|
138
|
+
}
|
|
139
|
+
changed = true;
|
|
80
140
|
} else if (event.type === 'action' && event.targetId === 'clear-btn') {
|
|
81
141
|
logs = ['Logs cleared.'];
|
|
82
|
-
|
|
142
|
+
changed = true;
|
|
143
|
+
} else if (event.type === 'key' && event.payload?.key === 'q' && event.payload?.shift) {
|
|
83
144
|
process.exit(0);
|
|
84
145
|
}
|
|
85
|
-
|
|
146
|
+
|
|
147
|
+
if (changed) {
|
|
148
|
+
runtime.setDocument(getDashboardData());
|
|
149
|
+
}
|
|
86
150
|
});
|
|
87
151
|
|
|
88
|
-
|
|
152
|
+
runtime.setDocument(getDashboardData());
|
|
89
153
|
startTAUI(runtime);
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"@taui-standard/ink-adapter": "1.0.4",
|
|
14
14
|
"@taui-standard/validator": "1.0.4",
|
|
15
15
|
"tsx": "^4.7.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^20.11.0",
|
|
19
|
+
"@types/react": "^18.2.0"
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
"node_modules/@alcalzone/ansi-tokenize": {
|
|
@@ -477,6 +481,34 @@
|
|
|
477
481
|
"zod": "^3.22.4"
|
|
478
482
|
}
|
|
479
483
|
},
|
|
484
|
+
"node_modules/@types/node": {
|
|
485
|
+
"version": "20.19.30",
|
|
486
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz",
|
|
487
|
+
"integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==",
|
|
488
|
+
"dev": true,
|
|
489
|
+
"license": "MIT",
|
|
490
|
+
"dependencies": {
|
|
491
|
+
"undici-types": "~6.21.0"
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
"node_modules/@types/prop-types": {
|
|
495
|
+
"version": "15.7.15",
|
|
496
|
+
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
|
497
|
+
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
|
498
|
+
"devOptional": true,
|
|
499
|
+
"license": "MIT"
|
|
500
|
+
},
|
|
501
|
+
"node_modules/@types/react": {
|
|
502
|
+
"version": "18.3.27",
|
|
503
|
+
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
|
504
|
+
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
|
505
|
+
"devOptional": true,
|
|
506
|
+
"license": "MIT",
|
|
507
|
+
"dependencies": {
|
|
508
|
+
"@types/prop-types": "*",
|
|
509
|
+
"csstype": "^3.2.2"
|
|
510
|
+
}
|
|
511
|
+
},
|
|
480
512
|
"node_modules/ajv": {
|
|
481
513
|
"version": "8.17.1",
|
|
482
514
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
|
@@ -653,6 +685,13 @@
|
|
|
653
685
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
654
686
|
}
|
|
655
687
|
},
|
|
688
|
+
"node_modules/csstype": {
|
|
689
|
+
"version": "3.2.3",
|
|
690
|
+
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
|
691
|
+
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
|
692
|
+
"devOptional": true,
|
|
693
|
+
"license": "MIT"
|
|
694
|
+
},
|
|
656
695
|
"node_modules/emoji-regex": {
|
|
657
696
|
"version": "10.6.0",
|
|
658
697
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
|
@@ -1135,6 +1174,13 @@
|
|
|
1135
1174
|
"url": "https://github.com/sponsors/sindresorhus"
|
|
1136
1175
|
}
|
|
1137
1176
|
},
|
|
1177
|
+
"node_modules/undici-types": {
|
|
1178
|
+
"version": "6.21.0",
|
|
1179
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
|
1180
|
+
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
1181
|
+
"dev": true,
|
|
1182
|
+
"license": "MIT"
|
|
1183
|
+
},
|
|
1138
1184
|
"node_modules/widest-line": {
|
|
1139
1185
|
"version": "5.0.0",
|
|
1140
1186
|
"resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz",
|
package/package.json
CHANGED
package/src/renderer.tsx
CHANGED
|
@@ -50,7 +50,7 @@ export const TAUIBox: React.FC<RendererProps> = ({ node, runtime }) => {
|
|
|
50
50
|
>
|
|
51
51
|
{node.type === 'Panel' && node.title && (
|
|
52
52
|
<Box position="absolute" marginTop={-1} marginLeft={1} paddingX={1}>
|
|
53
|
-
<Text bold>{node.title}</Text>
|
|
53
|
+
<Text bold color={node.style?.color}>{node.title}</Text>
|
|
54
54
|
</Box>
|
|
55
55
|
)}
|
|
56
56
|
{node.children?.map((child: TAUINode, idx: number) => (
|
|
@@ -74,8 +74,8 @@ export const TAUIButton: React.FC<RendererProps> = ({ node, runtime }) => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
return (
|
|
77
|
-
<Box borderStyle="round" borderColor={isFocused ? '
|
|
78
|
-
<Text color={isFocused
|
|
77
|
+
<Box borderStyle="round" borderColor={isFocused ? (node.style?.color || 'white') : (node.style?.color || 'gray')} paddingX={1}>
|
|
78
|
+
<Text color={node.style?.color} bold={isFocused}>{node.label}</Text>
|
|
79
79
|
</Box>
|
|
80
80
|
);
|
|
81
81
|
};
|
|
@@ -95,17 +95,66 @@ export const TAUIInput: React.FC<RendererProps> = ({ node, runtime }) => {
|
|
|
95
95
|
return (
|
|
96
96
|
<Box flexDirection="row" gap={1}>
|
|
97
97
|
{node.placeholder && <Text dimColor>{node.placeholder}: </Text>}
|
|
98
|
-
<Box borderStyle="single" borderColor={isFocused ? '
|
|
98
|
+
<Box borderStyle="single" borderColor={isFocused ? (node.style?.color || 'white') : (node.style?.color || 'gray')} paddingX={1} minWidth={10}>
|
|
99
99
|
{isFocused ? (
|
|
100
100
|
<TextInput value={node.value || ''} onChange={onChange} mask={node.mask ? '*' : undefined} />
|
|
101
101
|
) : (
|
|
102
|
-
<Text>{node.mask ? '*'.repeat((node.value || '').length) : (node.value || ' ')}</Text>
|
|
102
|
+
<Text color={node.style?.color}>{node.mask ? '*'.repeat((node.value || '').length) : (node.value || ' ')}</Text>
|
|
103
103
|
)}
|
|
104
104
|
</Box>
|
|
105
105
|
</Box>
|
|
106
106
|
);
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
+
export const TAUISelect: React.FC<RendererProps> = ({ node, runtime }) => {
|
|
110
|
+
const { isFocused } = useFocus({ id: node.id });
|
|
111
|
+
const options = (node as any).options || [];
|
|
112
|
+
const currentValue = (node as any).value;
|
|
113
|
+
const currentIndex = options.findIndex((opt: any) => opt.value === currentValue);
|
|
114
|
+
|
|
115
|
+
useInput((input, key) => {
|
|
116
|
+
if (isFocused) {
|
|
117
|
+
if (key.upArrow || key.leftArrow) {
|
|
118
|
+
const nextIndex = (currentIndex - 1 + options.length) % options.length;
|
|
119
|
+
runtime.dispatchRawEvent({
|
|
120
|
+
type: 'change',
|
|
121
|
+
targetId: node.id,
|
|
122
|
+
payload: { value: options[nextIndex].value },
|
|
123
|
+
timestamp: new Date().toISOString()
|
|
124
|
+
});
|
|
125
|
+
} else if (key.downArrow || key.rightArrow) {
|
|
126
|
+
const nextIndex = (currentIndex + 1) % options.length;
|
|
127
|
+
runtime.dispatchRawEvent({
|
|
128
|
+
type: 'change',
|
|
129
|
+
targetId: node.id,
|
|
130
|
+
payload: { value: options[nextIndex].value },
|
|
131
|
+
timestamp: new Date().toISOString()
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Box flexDirection="row" gap={1}>
|
|
139
|
+
{options.map((opt: any, i: number) => {
|
|
140
|
+
const isSelected = opt.value === currentValue;
|
|
141
|
+
return (
|
|
142
|
+
<Box
|
|
143
|
+
key={i}
|
|
144
|
+
borderStyle="single"
|
|
145
|
+
borderColor={isFocused && isSelected ? (node.style?.color || 'white') : 'gray'}
|
|
146
|
+
paddingX={1}
|
|
147
|
+
>
|
|
148
|
+
<Text color={node.style?.color} bold={isSelected}>
|
|
149
|
+
{isSelected ? '> ' : ''}{opt.label}
|
|
150
|
+
</Text>
|
|
151
|
+
</Box>
|
|
152
|
+
);
|
|
153
|
+
})}
|
|
154
|
+
</Box>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
109
158
|
export const TAUIProgress: React.FC<RendererProps> = ({ node }) => {
|
|
110
159
|
const width = 20;
|
|
111
160
|
const val = (node as any).value || 0;
|
|
@@ -114,9 +163,9 @@ export const TAUIProgress: React.FC<RendererProps> = ({ node }) => {
|
|
|
114
163
|
|
|
115
164
|
return (
|
|
116
165
|
<Box flexDirection="row" gap={1}>
|
|
117
|
-
{(node as any).label && <Text>{(node as any).label}</Text>}
|
|
118
|
-
<Text color=
|
|
119
|
-
<Text>{Math.round(val * 100)}%</Text>
|
|
166
|
+
{(node as any).label && <Text color={node.style?.color}>{(node as any).label}</Text>}
|
|
167
|
+
<Text color={node.style?.color}>{bar}</Text>
|
|
168
|
+
<Text color={node.style?.color}>{Math.round(val * 100)}%</Text>
|
|
120
169
|
</Box>
|
|
121
170
|
);
|
|
122
171
|
};
|
|
@@ -163,7 +212,7 @@ export const TAUITable: React.FC<RendererProps> = ({ node }) => {
|
|
|
163
212
|
<Box flexDirection="row" borderStyle="single" borderBottom>
|
|
164
213
|
{headers.map((h: string, i: number) => (
|
|
165
214
|
<Box key={i} flexGrow={1} minWidth={10}>
|
|
166
|
-
<Text bold color=
|
|
215
|
+
<Text bold color={node.style?.color}>{h}</Text>
|
|
167
216
|
</Box>
|
|
168
217
|
))}
|
|
169
218
|
</Box>
|
|
@@ -171,7 +220,7 @@ export const TAUITable: React.FC<RendererProps> = ({ node }) => {
|
|
|
171
220
|
<Box key={i} flexDirection="row">
|
|
172
221
|
{row.map((cell: string, j: number) => (
|
|
173
222
|
<Box key={j} flexGrow={1} minWidth={10}>
|
|
174
|
-
<Text>{cell}</Text>
|
|
223
|
+
<Text color={node.style?.color}>{cell}</Text>
|
|
175
224
|
</Box>
|
|
176
225
|
))}
|
|
177
226
|
</Box>
|
|
@@ -186,7 +235,7 @@ export const TAUILog: React.FC<RendererProps> = ({ node }) => {
|
|
|
186
235
|
return (
|
|
187
236
|
<Box flexDirection="column" borderStyle="single" paddingX={1}>
|
|
188
237
|
{lines.slice(-(node.maxLines || 100)).map((line: string, i: number) => (
|
|
189
|
-
<Text key={i}>{line}</Text>
|
|
238
|
+
<Text key={i} color={node.style?.color}>{line}</Text>
|
|
190
239
|
))}
|
|
191
240
|
</Box>
|
|
192
241
|
);
|
|
@@ -207,6 +256,8 @@ export const TAUIRenderer: React.FC<RendererProps> = (props) => {
|
|
|
207
256
|
return <TAUIButton {...props} />;
|
|
208
257
|
case 'Input':
|
|
209
258
|
return <TAUIInput {...props} />;
|
|
259
|
+
case 'Select':
|
|
260
|
+
return <TAUISelect {...props} />;
|
|
210
261
|
case 'Progress':
|
|
211
262
|
return <TAUIProgress {...props} />;
|
|
212
263
|
case 'Table':
|
|
Binary file
|