@kal-elsam/kairo-runtime 0.10.0 → 0.11.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/package.json +1 -1
- package/scripts/cockpit-smoke.mjs +1 -1
- package/src/global/ink/brand/wordmark.js +50 -0
- package/src/global/ink/cockpit/primitives.js +45 -35
- package/src/global/ink/cockpit-views.js +2 -1
- package/src/global/ink/orchestrator-app.js +12 -4
- package/src/global/ink/theme.js +13 -8
- package/src/global/ink/ux/live-activity.js +4 -7
- package/src/global/ink/ux/live-alerts.js +2 -5
- package/src/global/ink/ux/live-governance.js +2 -6
- package/src/global/ink/ux/live-orchestration.js +2 -5
- package/src/global/ink/ux/live-overview.js +77 -27
- package/src/global/ink/ux/live-settings.js +3 -6
- package/src/global/ink/ux/live-usage.js +5 -7
- package/src/global/ink/ux/semantic.js +23 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kal-elsam/kairo-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Kairo Runtime — local agent operating system for Codex, Cursor, Claude, Pi, Engram, and Graphify.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/Kal-elSam/harness#readme",
|
|
@@ -26,7 +26,7 @@ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
26
26
|
const require = createRequire(import.meta.url);
|
|
27
27
|
const pkg = require(join(root, "package.json"));
|
|
28
28
|
|
|
29
|
-
assert.equal(pkg.version, "0.
|
|
29
|
+
assert.equal(pkg.version, "0.11.0");
|
|
30
30
|
assert.ok(pkg.dependencies["ansi-escapes"]);
|
|
31
31
|
|
|
32
32
|
assert.equal(resolveLayoutMode({ columns: 120, rows: 40 }), LAYOUT_MODES.WIDE);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static ASCII wordmark for Kairo Overview — no figlet dependency.
|
|
3
|
+
* Hero art appears only on Overview (wide / compact); minimal stays textual.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { LAYOUT_MODES } from "../layout.js";
|
|
7
|
+
|
|
8
|
+
const WORDMARK_WIDE = [
|
|
9
|
+
"╦╔═╔═╗╦╦═╗╔═╗",
|
|
10
|
+
"╠╩╗╠═╣║╠╦╝║ ║",
|
|
11
|
+
"╩ ╩╩ ╩╩╩╚═╚═╝"
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const WORDMARK_COMPACT = [
|
|
15
|
+
"╦╔═╔═╗╦╦═╗╔═╗",
|
|
16
|
+
"╩ ╩╩ ╩╩╩╚═╚═╝"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const WORDMARK_WIDE_ASCII = [
|
|
20
|
+
"K A I R O",
|
|
21
|
+
"========="
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const WORDMARK_COMPACT_ASCII = [
|
|
25
|
+
"KAIRO"
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export function shouldShowWordmark(layoutMode) {
|
|
29
|
+
return layoutMode === LAYOUT_MODES.WIDE || layoutMode === LAYOUT_MODES.COMPACT;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {"wide"|"compact"|"minimal"|string} layoutMode
|
|
34
|
+
* @param {{ unicode?: boolean }} [opts]
|
|
35
|
+
* @returns {string[]}
|
|
36
|
+
*/
|
|
37
|
+
export function wordmarkLines(layoutMode, { unicode = true } = {}) {
|
|
38
|
+
if (layoutMode === LAYOUT_MODES.WIDE) {
|
|
39
|
+
return unicode ? WORDMARK_WIDE.slice() : WORDMARK_WIDE_ASCII.slice();
|
|
40
|
+
}
|
|
41
|
+
if (layoutMode === LAYOUT_MODES.COMPACT) {
|
|
42
|
+
return unicode ? WORDMARK_COMPACT.slice() : WORDMARK_COMPACT_ASCII.slice();
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function overviewBrandTitle(layoutMode) {
|
|
48
|
+
if (shouldShowWordmark(layoutMode)) return null;
|
|
49
|
+
return "KAIRO · Overview";
|
|
50
|
+
}
|
|
@@ -12,7 +12,7 @@ export function CockpitEmptyState({ title, message, hint, colorEnabled = true })
|
|
|
12
12
|
return React.createElement(Box, { flexDirection: "column", marginY: 1 },
|
|
13
13
|
title && React.createElement(Text, {
|
|
14
14
|
bold: true,
|
|
15
|
-
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.
|
|
15
|
+
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.brand)
|
|
16
16
|
}, title),
|
|
17
17
|
message && React.createElement(Text, null, message),
|
|
18
18
|
hint && React.createElement(Text, {
|
|
@@ -21,23 +21,20 @@ export function CockpitEmptyState({ title, message, hint, colorEnabled = true })
|
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/** Content region — no border; focus is conveyed by interactive children. */
|
|
24
25
|
export function CockpitPanel({ title, focused = false, width, children, colorEnabled = true }) {
|
|
25
26
|
return React.createElement(Box, {
|
|
26
27
|
flexDirection: "column",
|
|
27
28
|
width,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
colorEnabled,
|
|
31
|
-
focused ? COCKPIT_COLORS.primary : COCKPIT_COLORS.muted
|
|
32
|
-
),
|
|
33
|
-
paddingX: 1,
|
|
29
|
+
paddingX: 0,
|
|
30
|
+
marginY: 1,
|
|
34
31
|
flexGrow: 1
|
|
35
32
|
},
|
|
36
33
|
title && React.createElement(Text, {
|
|
37
34
|
bold: true,
|
|
38
35
|
color: resolveInkColor(
|
|
39
36
|
colorEnabled,
|
|
40
|
-
focused ? COCKPIT_COLORS.
|
|
37
|
+
focused ? COCKPIT_COLORS.interactive : COCKPIT_COLORS.brand
|
|
41
38
|
)
|
|
42
39
|
}, title),
|
|
43
40
|
children
|
|
@@ -48,7 +45,7 @@ export function CockpitSection({ title, children, colorEnabled = true }) {
|
|
|
48
45
|
return React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
49
46
|
title && React.createElement(Text, {
|
|
50
47
|
bold: true,
|
|
51
|
-
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.
|
|
48
|
+
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.brand)
|
|
52
49
|
}, title),
|
|
53
50
|
children
|
|
54
51
|
);
|
|
@@ -60,15 +57,29 @@ export function CockpitKeyHint({ keys, label, colorEnabled = true }) {
|
|
|
60
57
|
}, `${keys} ${label}`);
|
|
61
58
|
}
|
|
62
59
|
|
|
60
|
+
/** Compact header: brand · status · project — no box-drawing. */
|
|
63
61
|
export function CockpitTopBar({ model, colorEnabled = true }) {
|
|
62
|
+
const statusKind = String(model.status ?? "").toUpperCase() === "ONLINE"
|
|
63
|
+
? "online"
|
|
64
|
+
: "muted";
|
|
64
65
|
return React.createElement(Box, { justifyContent: "space-between", width: "100%" },
|
|
65
|
-
React.createElement(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
React.createElement(Box, null,
|
|
67
|
+
React.createElement(Text, {
|
|
68
|
+
bold: true,
|
|
69
|
+
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.brand)
|
|
70
|
+
}, model.brand),
|
|
71
|
+
React.createElement(Text, {
|
|
72
|
+
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.muted)
|
|
73
|
+
}, " · "),
|
|
74
|
+
React.createElement(CockpitBadge, {
|
|
75
|
+
label: model.status,
|
|
76
|
+
kind: statusKind,
|
|
77
|
+
colorEnabled
|
|
78
|
+
})
|
|
79
|
+
),
|
|
69
80
|
React.createElement(Text, {
|
|
70
81
|
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.muted)
|
|
71
|
-
},
|
|
82
|
+
}, model.projectLabel)
|
|
72
83
|
);
|
|
73
84
|
}
|
|
74
85
|
|
|
@@ -78,9 +89,9 @@ export function CockpitNav({ model, colorEnabled = true }) {
|
|
|
78
89
|
model.items.map((item) => {
|
|
79
90
|
const suffix = item.current && !item.selected ? " (open)" : "";
|
|
80
91
|
const color = item.focused
|
|
81
|
-
? resolveInkColor(colorEnabled, COCKPIT_COLORS.
|
|
92
|
+
? resolveInkColor(colorEnabled, COCKPIT_COLORS.interactive)
|
|
82
93
|
: item.selected
|
|
83
|
-
? resolveInkColor(colorEnabled, COCKPIT_COLORS.
|
|
94
|
+
? resolveInkColor(colorEnabled, COCKPIT_COLORS.brand)
|
|
84
95
|
: item.current
|
|
85
96
|
? resolveInkColor(colorEnabled, COCKPIT_COLORS.muted)
|
|
86
97
|
: undefined;
|
|
@@ -101,7 +112,7 @@ function stripLabel(item, { compact }) {
|
|
|
101
112
|
return item.label.split(/[&·]/)[0].trim().split(/\s+/)[0];
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
/**
|
|
115
|
+
/** Segmented horizontal nav — no border; active segment uses interactive. */
|
|
105
116
|
export function CockpitNavStrip({
|
|
106
117
|
model,
|
|
107
118
|
colorEnabled = true,
|
|
@@ -112,16 +123,20 @@ export function CockpitNavStrip({
|
|
|
112
123
|
const parts = model.items.map((item) => {
|
|
113
124
|
const label = stripLabel(item, { compact });
|
|
114
125
|
const suffix = item.current && !item.selected ? "*" : "";
|
|
115
|
-
const
|
|
116
|
-
|
|
126
|
+
const active = item.focused || item.selected;
|
|
127
|
+
const color = item.focused || (focused && item.selected)
|
|
128
|
+
? resolveInkColor(colorEnabled, COCKPIT_COLORS.interactive)
|
|
117
129
|
: item.selected
|
|
118
|
-
? resolveInkColor(colorEnabled, COCKPIT_COLORS.
|
|
130
|
+
? resolveInkColor(colorEnabled, COCKPIT_COLORS.interactive)
|
|
119
131
|
: resolveInkColor(colorEnabled, COCKPIT_COLORS.muted);
|
|
132
|
+
const text = focused && item.selected
|
|
133
|
+
? `[${label}]${suffix}`
|
|
134
|
+
: `${item.marker}${label}${suffix}`;
|
|
120
135
|
return React.createElement(Text, {
|
|
121
136
|
key: item.id,
|
|
122
|
-
bold:
|
|
137
|
+
bold: active,
|
|
123
138
|
color
|
|
124
|
-
},
|
|
139
|
+
}, text);
|
|
125
140
|
});
|
|
126
141
|
|
|
127
142
|
const joined = [];
|
|
@@ -138,12 +153,8 @@ export function CockpitNavStrip({
|
|
|
138
153
|
return React.createElement(Box, {
|
|
139
154
|
flexDirection: "column",
|
|
140
155
|
width: "100%",
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
colorEnabled,
|
|
144
|
-
focused ? COCKPIT_COLORS.primary : COCKPIT_COLORS.muted
|
|
145
|
-
),
|
|
146
|
-
paddingX: 1
|
|
156
|
+
marginTop: 0,
|
|
157
|
+
marginBottom: 0
|
|
147
158
|
},
|
|
148
159
|
React.createElement(Box, { flexDirection: "row", flexWrap: "wrap" }, ...joined),
|
|
149
160
|
model.explanation && React.createElement(Text, {
|
|
@@ -170,20 +181,19 @@ export function CockpitSystemStrip({ model, colorEnabled = true }) {
|
|
|
170
181
|
);
|
|
171
182
|
}
|
|
172
183
|
|
|
184
|
+
/** Single-line shortcut bar — no framed box. */
|
|
173
185
|
export function CockpitFooter({ model, columns = 80, colorEnabled = true }) {
|
|
174
186
|
const width = Math.max(24, Math.min(Number(columns) || 80, 120));
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
React.createElement(Text, { color: muted }, `│ ${model.text}`),
|
|
180
|
-
React.createElement(Text, { color: muted }, `╰${"─".repeat(bar)}╯`)
|
|
187
|
+
return React.createElement(Box, { width: "100%", marginTop: 1 },
|
|
188
|
+
React.createElement(Text, {
|
|
189
|
+
color: resolveInkColor(colorEnabled, COCKPIT_COLORS.muted)
|
|
190
|
+
}, String(model.text ?? "").slice(0, width))
|
|
181
191
|
);
|
|
182
192
|
}
|
|
183
193
|
|
|
184
194
|
/**
|
|
185
195
|
* Responsive single-panel shell: TopBar → NavStrip → Main → Footer.
|
|
186
|
-
*
|
|
196
|
+
* No nested borders — hierarchy via type and spacing.
|
|
187
197
|
*/
|
|
188
198
|
export function CockpitShell({
|
|
189
199
|
topBar,
|
|
@@ -111,7 +111,8 @@ export function renderCockpitView({
|
|
|
111
111
|
model: controlCenter,
|
|
112
112
|
detailsOpen: overviewDetailsOpen,
|
|
113
113
|
colorEnabled,
|
|
114
|
-
unicode
|
|
114
|
+
unicode,
|
|
115
|
+
layoutMode
|
|
115
116
|
});
|
|
116
117
|
case ORCHESTRATOR_VIEWS.USAGE:
|
|
117
118
|
return React.createElement(SemanticUsagePanel, {
|
|
@@ -41,7 +41,7 @@ import { handleLaunchInput } from "./launch-input.js";
|
|
|
41
41
|
import { useTerminalSize } from "./use-terminal-size.js";
|
|
42
42
|
import { useOrchestratorData } from "./use-orchestrator-data.js";
|
|
43
43
|
import { resolveTerminalCapabilities } from "./terminal-capabilities.js";
|
|
44
|
-
import { COCKPIT_COLORS } from "./theme.js";
|
|
44
|
+
import { COCKPIT_COLORS, resolveInkColor } from "./theme.js";
|
|
45
45
|
import { LAYOUT_MODES } from "./layout.js";
|
|
46
46
|
import { CHANGES_PHASE } from "./cockpit-changes.js";
|
|
47
47
|
import { RECOVERY_PHASE, listRecoverySnapshots } from "./cockpit-recovery.js";
|
|
@@ -466,14 +466,22 @@ export function OrchestratorApp({
|
|
|
466
466
|
|
|
467
467
|
if (data.loading) {
|
|
468
468
|
return React.createElement(Box, { flexDirection: "column" },
|
|
469
|
-
React.createElement(Text, {
|
|
470
|
-
|
|
469
|
+
React.createElement(Text, {
|
|
470
|
+
bold: true,
|
|
471
|
+
color: resolveInkColor(caps.color, COCKPIT_COLORS.brand)
|
|
472
|
+
}, "KAIRO"),
|
|
473
|
+
React.createElement(Text, {
|
|
474
|
+
color: resolveInkColor(caps.color, COCKPIT_COLORS.muted)
|
|
475
|
+
}, "Loading cockpit…")
|
|
471
476
|
);
|
|
472
477
|
}
|
|
473
478
|
|
|
474
479
|
if (data.error) {
|
|
475
480
|
return React.createElement(Box, { flexDirection: "column" },
|
|
476
|
-
React.createElement(Text, {
|
|
481
|
+
React.createElement(Text, {
|
|
482
|
+
bold: true,
|
|
483
|
+
color: resolveInkColor(caps.color, COCKPIT_COLORS.danger)
|
|
484
|
+
}, "Runtime error"),
|
|
477
485
|
React.createElement(Text, null, data.error),
|
|
478
486
|
React.createElement(Text, { dimColor: true },
|
|
479
487
|
data.retrying ? "Retrying read-only scan…" : "R Retry · Esc to exit")
|
package/src/global/ink/theme.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Kairo Cockpit theme — amber brand, ice interactive, semantic status.
|
|
3
|
+
* Status always has a text label — never color alone.
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
6
|
export const COCKPIT_COLORS = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
success: "
|
|
9
|
-
warning: "
|
|
10
|
-
danger: "
|
|
7
|
+
brand: "#E8A017",
|
|
8
|
+
interactive: "#7EC8E8",
|
|
9
|
+
success: "#3DDC97",
|
|
10
|
+
warning: "#F0C674",
|
|
11
|
+
danger: "#FF6B6B",
|
|
11
12
|
muted: "gray",
|
|
12
|
-
|
|
13
|
+
/** @deprecated alias — prefer interactive */
|
|
14
|
+
primary: "#7EC8E8",
|
|
15
|
+
/** @deprecated alias — prefer brand */
|
|
16
|
+
secondary: "#E8A017",
|
|
17
|
+
border: "#7EC8E8"
|
|
13
18
|
};
|
|
14
19
|
|
|
15
20
|
export const STATUS_LABELS = {
|
|
@@ -69,7 +74,7 @@ export function statusColor(kind, { colorEnabled = true } = {}) {
|
|
|
69
74
|
case "muted":
|
|
70
75
|
return COCKPIT_COLORS.muted;
|
|
71
76
|
default:
|
|
72
|
-
return COCKPIT_COLORS.
|
|
77
|
+
return COCKPIT_COLORS.interactive;
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/** Live semantic Activity/Recovery. Callout=status · Confirm=action · footer=keys · snapshots=focus. */
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Box, Text } from "ink";
|
|
4
|
-
import { COCKPIT_COLORS } from "../theme.js";
|
|
5
4
|
import { formatConfirmPath } from "../cockpit-path-label.js";
|
|
6
5
|
import {
|
|
7
6
|
RECOVERY_PHASE, listRecoverySnapshots, formatWhen, formatResult, shortName
|
|
8
7
|
} from "../cockpit-recovery.js";
|
|
9
8
|
import { LAYOUT_MODES } from "../layout.js";
|
|
10
|
-
import { ActionList, Callout, Confirm, Details } from "./semantic.js";
|
|
9
|
+
import { ActionList, Callout, Confirm, Details, SectionLabel, ViewTitle } from "./semantic.js";
|
|
11
10
|
import { detailsPathLimit } from "./live-governance.js";
|
|
12
11
|
|
|
13
12
|
export function activityContentLimits(layoutMode = LAYOUT_MODES.COMPACT) {
|
|
@@ -157,9 +156,7 @@ export function SemanticActivityPanel({
|
|
|
157
156
|
snapshot, recoveryAction, dashboard, listIndex, homeDir, detailsOpen, layoutMode
|
|
158
157
|
});
|
|
159
158
|
return React.createElement(Box, { flexDirection: "column" },
|
|
160
|
-
React.createElement(
|
|
161
|
-
bold: true, color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
162
|
-
}, view.title),
|
|
159
|
+
React.createElement(ViewTitle, { colorEnabled }, view.title),
|
|
163
160
|
React.createElement(Callout, {
|
|
164
161
|
tone: view.callout.tone, title: view.callout.title,
|
|
165
162
|
body: view.callout.body || undefined, colorEnabled, compact: true
|
|
@@ -174,11 +171,11 @@ export function SemanticActivityPanel({
|
|
|
174
171
|
: null,
|
|
175
172
|
view.primary?.detail && !view.confirm
|
|
176
173
|
? React.createElement(Text, null, view.primary.detail) : null,
|
|
177
|
-
React.createElement(
|
|
174
|
+
React.createElement(SectionLabel, { colorEnabled }, "Recent"),
|
|
178
175
|
React.createElement(ActionList, {
|
|
179
176
|
items: view.recent, selectedIndex: -1, focused: false, colorEnabled, unicode
|
|
180
177
|
}),
|
|
181
|
-
React.createElement(
|
|
178
|
+
React.createElement(SectionLabel, { colorEnabled }, "Snapshots"),
|
|
182
179
|
React.createElement(ActionList, {
|
|
183
180
|
items: view.snapshots, selectedIndex: view.selectedIndex,
|
|
184
181
|
focused: contentFocused, colorEnabled, unicode
|
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { Box, Text } from "ink";
|
|
8
|
-
import { COCKPIT_COLORS } from "../theme.js";
|
|
9
8
|
import { LAYOUT_MODES } from "../layout.js";
|
|
10
9
|
import { ALERT_STATES } from "../../runtime/alerts/alert-types.js";
|
|
11
10
|
import { formatAlertsHeadline, selectAlertFromList } from "../cockpit-alerts.js";
|
|
12
|
-
import { ActionList, Callout } from "./semantic.js";
|
|
11
|
+
import { ActionList, Callout, ViewTitle } from "./semantic.js";
|
|
13
12
|
import { windowSlice } from "./live-activity.js";
|
|
14
13
|
|
|
15
14
|
export function alertsListLimit(layoutMode = LAYOUT_MODES.COMPACT) {
|
|
@@ -138,9 +137,7 @@ export function SemanticAlertsPanel({
|
|
|
138
137
|
const model = adaptAlertsModel({ alerts, listIndex, layoutMode });
|
|
139
138
|
const listFocused = contentFocused && !model.isEmpty && !model.isUnavailable;
|
|
140
139
|
return React.createElement(Box, { flexDirection: "column" },
|
|
141
|
-
React.createElement(
|
|
142
|
-
bold: true, color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
143
|
-
}, model.title),
|
|
140
|
+
React.createElement(ViewTitle, { colorEnabled }, model.title),
|
|
144
141
|
React.createElement(Callout, {
|
|
145
142
|
tone: model.callout.tone,
|
|
146
143
|
title: model.callout.title,
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/** Live semantic Governance. Ownership: Callout=status · Confirm/primary=action · footer=keys. */
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Box, Text } from "ink";
|
|
4
|
-
import { COCKPIT_COLORS } from "../theme.js";
|
|
5
4
|
import { formatConfirmPath } from "../cockpit-path-label.js";
|
|
6
5
|
import { CHANGES_PHASE } from "../cockpit-changes.js";
|
|
7
6
|
import { LAYOUT_MODES } from "../layout.js";
|
|
8
|
-
import { ActionList, Callout, Confirm, Details } from "./semantic.js";
|
|
7
|
+
import { ActionList, Callout, Confirm, Details, ViewTitle } from "./semantic.js";
|
|
9
8
|
import { mapHealthTone } from "./live-overview.js";
|
|
10
9
|
|
|
11
10
|
function healthLabel(kind) {
|
|
@@ -151,10 +150,7 @@ export function SemanticGovernancePanel({
|
|
|
151
150
|
snapshot, changesAction, homeDir, detailsOpen, layoutMode
|
|
152
151
|
});
|
|
153
152
|
return React.createElement(Box, { flexDirection: "column" },
|
|
154
|
-
React.createElement(
|
|
155
|
-
bold: true,
|
|
156
|
-
color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
157
|
-
}, view.title),
|
|
153
|
+
React.createElement(ViewTitle, { colorEnabled }, view.title),
|
|
158
154
|
React.createElement(Callout, {
|
|
159
155
|
tone: view.callout.tone,
|
|
160
156
|
title: view.callout.title,
|
|
@@ -5,14 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { Box, Text } from "ink";
|
|
8
|
-
import { COCKPIT_COLORS } from "../theme.js";
|
|
9
8
|
import { LAYOUT_MODES } from "../layout.js";
|
|
10
9
|
import { ORCHESTRATOR_VIEWS, formatRunLines } from "../orchestrator-state.js";
|
|
11
10
|
import {
|
|
12
11
|
RUNS_HUB_ITEMS, formatOrchestrationStatus, formatRunsHubLines
|
|
13
12
|
} from "../cockpit-runs.js";
|
|
14
13
|
import { formatReviewListLines } from "../cockpit-reviews.js";
|
|
15
|
-
import { ActionList, Callout } from "./semantic.js";
|
|
14
|
+
import { ActionList, Callout, ViewTitle } from "./semantic.js";
|
|
16
15
|
import { windowSlice } from "./live-activity.js";
|
|
17
16
|
|
|
18
17
|
export function orchestrationListLimit(layoutMode = LAYOUT_MODES.COMPACT) {
|
|
@@ -167,9 +166,7 @@ export function SemanticOrchestrationPanel({
|
|
|
167
166
|
});
|
|
168
167
|
const listFocused = contentFocused && !model.isEmpty;
|
|
169
168
|
return React.createElement(Box, { flexDirection: "column" },
|
|
170
|
-
React.createElement(
|
|
171
|
-
bold: true, color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
172
|
-
}, model.title),
|
|
169
|
+
React.createElement(ViewTitle, { colorEnabled }, model.title),
|
|
173
170
|
React.createElement(Callout, {
|
|
174
171
|
tone: model.callout.tone,
|
|
175
172
|
title: model.callout.title,
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Live semantic Overview for Cockpit HOME.
|
|
2
|
+
* Live semantic Overview for Cockpit HOME — product cover.
|
|
3
3
|
* Nav owns the sole focus mark — this panel never renders `>`.
|
|
4
|
+
* ASCII wordmark only here (wide/compact); minimal is textual.
|
|
4
5
|
*/
|
|
5
6
|
import React from "react";
|
|
6
7
|
import { Box, Text } from "ink";
|
|
7
8
|
import { CONTROL_PLANE_HEALTH } from "../../control-plane-snapshot.js";
|
|
9
|
+
import { LAYOUT_MODES } from "../layout.js";
|
|
8
10
|
import { COCKPIT_COLORS } from "../theme.js";
|
|
11
|
+
import {
|
|
12
|
+
overviewBrandTitle,
|
|
13
|
+
shouldShowWordmark,
|
|
14
|
+
wordmarkLines
|
|
15
|
+
} from "../brand/wordmark.js";
|
|
9
16
|
import { ActionList, Callout, Details } from "./semantic.js";
|
|
10
17
|
|
|
11
18
|
const DESTINATION_LABELS = {
|
|
@@ -80,39 +87,82 @@ export function adaptControlCenterToOverview(model = {}) {
|
|
|
80
87
|
};
|
|
81
88
|
}
|
|
82
89
|
|
|
90
|
+
function renderWordmark({ layoutMode, colorEnabled = true, unicode = true }) {
|
|
91
|
+
const lines = wordmarkLines(layoutMode, { unicode });
|
|
92
|
+
if (lines.length === 0) return null;
|
|
93
|
+
return React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
|
|
94
|
+
...lines.map((line, i) => React.createElement(Text, {
|
|
95
|
+
key: `wm-${i}`,
|
|
96
|
+
bold: i === 0,
|
|
97
|
+
color: colorEnabled ? COCKPIT_COLORS.brand : undefined
|
|
98
|
+
}, line))
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function renderCallout(view, colorEnabled) {
|
|
103
|
+
return React.createElement(Callout, {
|
|
104
|
+
tone: view.callout.tone,
|
|
105
|
+
title: view.callout.title,
|
|
106
|
+
body: view.callout.body,
|
|
107
|
+
colorEnabled,
|
|
108
|
+
compact: true
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
83
112
|
export function SemanticOverviewPanel({
|
|
84
113
|
model,
|
|
85
114
|
detailsOpen = false,
|
|
86
115
|
colorEnabled = true,
|
|
87
|
-
unicode = true
|
|
116
|
+
unicode = true,
|
|
117
|
+
layoutMode = LAYOUT_MODES.COMPACT
|
|
88
118
|
}) {
|
|
89
119
|
const view = adaptControlCenterToOverview(model);
|
|
120
|
+
const showArt = shouldShowWordmark(layoutMode);
|
|
121
|
+
const brandTitle = overviewBrandTitle(layoutMode);
|
|
122
|
+
const isWide = layoutMode === LAYOUT_MODES.WIDE;
|
|
123
|
+
const mark = renderWordmark({ layoutMode, colorEnabled, unicode });
|
|
124
|
+
const status = renderCallout(view, colorEnabled);
|
|
125
|
+
|
|
126
|
+
const hero = showArt
|
|
127
|
+
? (isWide
|
|
128
|
+
? React.createElement(Box, { flexDirection: "row", marginBottom: 1 },
|
|
129
|
+
React.createElement(Box, { marginRight: 2 }, mark),
|
|
130
|
+
React.createElement(Box, { flexDirection: "column", flexGrow: 1 }, status)
|
|
131
|
+
)
|
|
132
|
+
: React.createElement(Box, { flexDirection: "column" }, mark, status))
|
|
133
|
+
: React.createElement(Box, { flexDirection: "column" },
|
|
134
|
+
React.createElement(Text, {
|
|
135
|
+
bold: true,
|
|
136
|
+
color: colorEnabled ? COCKPIT_COLORS.brand : undefined
|
|
137
|
+
}, brandTitle),
|
|
138
|
+
status
|
|
139
|
+
);
|
|
140
|
+
|
|
90
141
|
return React.createElement(Box, { flexDirection: "column" },
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}),
|
|
142
|
+
hero,
|
|
143
|
+
React.createElement(Box, { marginTop: 1, flexDirection: "column" },
|
|
144
|
+
React.createElement(Text, {
|
|
145
|
+
bold: true,
|
|
146
|
+
color: colorEnabled ? COCKPIT_COLORS.interactive : undefined
|
|
147
|
+
}, view.primary.label),
|
|
148
|
+
view.primary.detail
|
|
149
|
+
? React.createElement(Text, null, view.primary.detail)
|
|
150
|
+
: null,
|
|
151
|
+
view.primary.hint
|
|
152
|
+
? React.createElement(Text, {
|
|
153
|
+
color: colorEnabled ? COCKPIT_COLORS.muted : undefined
|
|
154
|
+
}, view.primary.hint)
|
|
155
|
+
: null
|
|
156
|
+
),
|
|
157
|
+
React.createElement(Box, { marginTop: 1, flexDirection: "column" },
|
|
158
|
+
React.createElement(ActionList, {
|
|
159
|
+
items: view.metrics,
|
|
160
|
+
selectedIndex: -1,
|
|
161
|
+
focused: false,
|
|
162
|
+
colorEnabled,
|
|
163
|
+
unicode
|
|
164
|
+
})
|
|
165
|
+
),
|
|
116
166
|
React.createElement(Details, {
|
|
117
167
|
open: detailsOpen,
|
|
118
168
|
summary: "Details",
|
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { Box, Text } from "ink";
|
|
7
|
-
import { COCKPIT_COLORS } from "../theme.js";
|
|
8
7
|
import { LAYOUT_MODES } from "../layout.js";
|
|
9
8
|
import {
|
|
10
9
|
SETTINGS_PHASE, getCuratedIntegration, listCuratedIntegrations
|
|
11
10
|
} from "../cockpit-settings.js";
|
|
12
|
-
import { ActionList, Callout, Confirm, Details, Receipt } from "./semantic.js";
|
|
11
|
+
import { ActionList, Callout, Confirm, Details, Receipt, SectionLabel, ViewTitle } from "./semantic.js";
|
|
13
12
|
import { windowSlice } from "./live-activity.js";
|
|
14
13
|
|
|
15
14
|
export function settingsListLimit(layoutMode = LAYOUT_MODES.COMPACT) {
|
|
@@ -160,9 +159,7 @@ export function SemanticSettingsPanel({
|
|
|
160
159
|
model.receipt && React.createElement(Receipt, {
|
|
161
160
|
title: model.receipt.title, lines: model.receipt.lines, colorEnabled
|
|
162
161
|
}),
|
|
163
|
-
React.createElement(
|
|
164
|
-
bold: true, color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
165
|
-
}, model.title),
|
|
162
|
+
React.createElement(ViewTitle, { colorEnabled }, model.title),
|
|
166
163
|
React.createElement(Callout, {
|
|
167
164
|
tone: model.callout.tone, title: model.callout.title,
|
|
168
165
|
body: model.callout.body || undefined, colorEnabled, compact: true
|
|
@@ -176,7 +173,7 @@ export function SemanticSettingsPanel({
|
|
|
176
173
|
focused: listFocused, colorEnabled, unicode
|
|
177
174
|
}),
|
|
178
175
|
model.profilePolicy.length > 0 && React.createElement(Box, { flexDirection: "column" },
|
|
179
|
-
React.createElement(
|
|
176
|
+
React.createElement(SectionLabel, { colorEnabled }, "Profile & Policy"),
|
|
180
177
|
React.createElement(ActionList, {
|
|
181
178
|
items: model.profilePolicy, selectedIndex: -1, focused: false, colorEnabled, unicode
|
|
182
179
|
})
|
|
@@ -7,7 +7,7 @@ import { Box, Text } from "ink";
|
|
|
7
7
|
import { COCKPIT_COLORS } from "../theme.js";
|
|
8
8
|
import { LAYOUT_MODES } from "../layout.js";
|
|
9
9
|
import { adaptUsageModel } from "../cockpit-usage.js";
|
|
10
|
-
import { ActionList, Callout } from "./semantic.js";
|
|
10
|
+
import { ActionList, Callout, SectionLabel, ViewTitle } from "./semantic.js";
|
|
11
11
|
|
|
12
12
|
export function SemanticUsagePanel({
|
|
13
13
|
snapshot = null,
|
|
@@ -19,9 +19,7 @@ export function SemanticUsagePanel({
|
|
|
19
19
|
const model = adaptUsageModel({ snapshot, dashboard, layoutMode });
|
|
20
20
|
const muted = colorEnabled ? COCKPIT_COLORS.muted : undefined;
|
|
21
21
|
return React.createElement(Box, { flexDirection: "column" },
|
|
22
|
-
React.createElement(
|
|
23
|
-
bold: true, color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
24
|
-
}, model.title),
|
|
22
|
+
React.createElement(ViewTitle, { colorEnabled }, model.title),
|
|
25
23
|
React.createElement(Callout, {
|
|
26
24
|
tone: model.callout.tone,
|
|
27
25
|
title: model.callout.title,
|
|
@@ -29,11 +27,11 @@ export function SemanticUsagePanel({
|
|
|
29
27
|
colorEnabled,
|
|
30
28
|
compact: true
|
|
31
29
|
}),
|
|
32
|
-
React.createElement(
|
|
30
|
+
React.createElement(SectionLabel, { colorEnabled }, "Measured"),
|
|
33
31
|
React.createElement(Text, null, ` ${model.measured}`),
|
|
34
|
-
React.createElement(
|
|
32
|
+
React.createElement(SectionLabel, { colorEnabled }, "Configured limits"),
|
|
35
33
|
React.createElement(Text, null, ` ${model.configured}`),
|
|
36
|
-
React.createElement(
|
|
34
|
+
React.createElement(SectionLabel, { colorEnabled }, "Run usage"),
|
|
37
35
|
model.runs.length === 0
|
|
38
36
|
? React.createElement(Text, null, " No auditable run tokenUsage yet.")
|
|
39
37
|
: React.createElement(ActionList, {
|
|
@@ -4,6 +4,15 @@ import { Box, Text } from "ink";
|
|
|
4
4
|
import { COCKPIT_COLORS, statusColor, resolveGlyphs } from "../theme.js";
|
|
5
5
|
|
|
6
6
|
const mute = (on) => (on ? COCKPIT_COLORS.muted : undefined);
|
|
7
|
+
const ice = (on) => (on ? COCKPIT_COLORS.interactive : undefined);
|
|
8
|
+
|
|
9
|
+
/** Short typographic view title — brand amber, no border. */
|
|
10
|
+
export function ViewTitle({ children, colorEnabled = true }) {
|
|
11
|
+
return React.createElement(Text, {
|
|
12
|
+
bold: true,
|
|
13
|
+
color: colorEnabled ? COCKPIT_COLORS.brand : undefined
|
|
14
|
+
}, children);
|
|
15
|
+
}
|
|
7
16
|
|
|
8
17
|
export function ActionList({ items = [], selectedIndex = 0, focused = true, colorEnabled = true, unicode = true }) {
|
|
9
18
|
const g = resolveGlyphs(unicode);
|
|
@@ -13,7 +22,7 @@ export function ActionList({ items = [], selectedIndex = 0, focused = true, colo
|
|
|
13
22
|
return React.createElement(Text, {
|
|
14
23
|
key: item.id ?? String(i),
|
|
15
24
|
bold: sel,
|
|
16
|
-
color: sel && focused && colorEnabled ? COCKPIT_COLORS.
|
|
25
|
+
color: sel && focused && colorEnabled ? COCKPIT_COLORS.interactive : undefined
|
|
17
26
|
}, `${sel && focused ? g.focus : " "} ${item.label}${item.hint ? ` ${item.hint}` : ""}`);
|
|
18
27
|
})
|
|
19
28
|
);
|
|
@@ -30,7 +39,7 @@ export function Stepper({ steps = [], currentIndex = 0, colorEnabled = true, uni
|
|
|
30
39
|
const cur = i === currentIndex;
|
|
31
40
|
const color = isDone
|
|
32
41
|
? (colorEnabled ? COCKPIT_COLORS.success : undefined)
|
|
33
|
-
: cur ? (colorEnabled
|
|
42
|
+
: cur ? ice(colorEnabled) : mute(colorEnabled);
|
|
34
43
|
return React.createElement(Text, {
|
|
35
44
|
key: step.id ?? String(i), bold: cur, color
|
|
36
45
|
}, `${isDone ? done : cur ? current : idle} ${i + 1}. ${step.label}`);
|
|
@@ -50,24 +59,24 @@ export function Callout({ tone = "info", title, body, colorEnabled = true, compa
|
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
export function Confirm({ summary, primaryLabel = "Confirm", focused = true, colorEnabled = true, mark = " " }) {
|
|
53
|
-
return React.createElement(Box, { flexDirection: "column" },
|
|
62
|
+
return React.createElement(Box, { flexDirection: "column", marginY: 1 },
|
|
54
63
|
summary ? React.createElement(Text, null, summary) : null,
|
|
55
64
|
React.createElement(Text, {
|
|
56
65
|
bold: focused,
|
|
57
|
-
color: focused && colorEnabled ? COCKPIT_COLORS.
|
|
66
|
+
color: focused && colorEnabled ? COCKPIT_COLORS.interactive : undefined
|
|
58
67
|
}, `${mark} ${primaryLabel}`)
|
|
59
68
|
);
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
export function Receipt({ title = "Receipt", lines = [], colorEnabled = true }) {
|
|
63
|
-
return React.createElement(Box, { flexDirection: "column" },
|
|
72
|
+
return React.createElement(Box, { flexDirection: "column", marginY: 1 },
|
|
64
73
|
React.createElement(Text, { bold: true, color: colorEnabled ? COCKPIT_COLORS.success : undefined }, title),
|
|
65
74
|
...lines.map((line, i) => React.createElement(Text, { key: `r${i}`, color: mute(colorEnabled) }, line))
|
|
66
75
|
);
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
export function Details({ open = false, summary = "Details", lines = [], colorEnabled = true, focused = false, mark = " " }) {
|
|
70
|
-
const color = focused && colorEnabled ? COCKPIT_COLORS.
|
|
79
|
+
const color = focused && colorEnabled ? COCKPIT_COLORS.interactive : mute(colorEnabled);
|
|
71
80
|
if (!open) return React.createElement(Text, { bold: focused, color }, `${mark} ${summary} · Space`);
|
|
72
81
|
return React.createElement(Box, { flexDirection: "column" },
|
|
73
82
|
React.createElement(Text, { bold: true, color }, `${mark} ${summary}`),
|
|
@@ -82,3 +91,11 @@ export function KeyBar({ hints = [], colorEnabled = true, columns = 80 }) {
|
|
|
82
91
|
hints.map((h) => `${h.keys} ${h.label}`).join(" · "))
|
|
83
92
|
);
|
|
84
93
|
}
|
|
94
|
+
|
|
95
|
+
/** Section label inside a panel — muted brand hierarchy under ViewTitle. */
|
|
96
|
+
export function SectionLabel({ children, colorEnabled = true }) {
|
|
97
|
+
return React.createElement(Text, {
|
|
98
|
+
bold: true,
|
|
99
|
+
color: colorEnabled ? COCKPIT_COLORS.muted : undefined
|
|
100
|
+
}, children);
|
|
101
|
+
}
|