@kal-elsam/kairo-runtime 0.8.0 → 0.10.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/README.md +41 -15
- package/package.json +1 -1
- package/scripts/cockpit-smoke.mjs +6 -6
- package/scripts/ux-prototype-tty.mjs +9 -0
- package/src/cli.js +24 -1
- package/src/global/control-plane-proposals.js +2 -1
- package/src/global/control-plane-snapshot.js +1 -1
- package/src/global/global-doctor.js +2 -0
- package/src/global/ink/cockpit/primitives.js +127 -50
- package/src/global/ink/cockpit-alerts.js +36 -0
- package/src/global/ink/cockpit-changes.js +61 -37
- package/src/global/ink/cockpit-control-center.js +79 -53
- package/src/global/ink/cockpit-controller.js +98 -15
- package/src/global/ink/cockpit-enter.js +1 -0
- package/src/global/ink/cockpit-focus.js +4 -2
- package/src/global/ink/cockpit-models.js +100 -51
- package/src/global/ink/cockpit-palette.js +109 -0
- package/src/global/ink/cockpit-path-label.js +19 -0
- package/src/global/ink/cockpit-recovery.js +84 -18
- package/src/global/ink/cockpit-reviews.js +14 -10
- package/src/global/ink/cockpit-runs.js +13 -4
- package/src/global/ink/cockpit-settings.js +194 -0
- package/src/global/ink/cockpit-usage.js +111 -0
- package/src/global/ink/cockpit-views.js +119 -116
- package/src/global/ink/orchestrator-app.js +169 -46
- package/src/global/ink/orchestrator-state.js +24 -14
- package/src/global/ink/setup-app.js +55 -72
- package/src/global/ink/setup-state.js +16 -0
- package/src/global/ink/theme.js +27 -0
- package/src/global/ink/use-orchestrator-data.js +58 -0
- package/src/global/ink/ux/live-activity.js +194 -0
- package/src/global/ink/ux/live-alerts.js +159 -0
- package/src/global/ink/ux/live-governance.js +195 -0
- package/src/global/ink/ux/live-orchestration.js +188 -0
- package/src/global/ink/ux/live-overview.js +125 -0
- package/src/global/ink/ux/live-settings.js +189 -0
- package/src/global/ink/ux/live-setup.js +160 -0
- package/src/global/ink/ux/live-usage.js +51 -0
- package/src/global/ink/ux/semantic.js +84 -0
- package/src/global/ink/ux/task-flow-app.js +85 -0
- package/src/global/ink/ux/task-flow.js +173 -0
- package/src/global/orchestrator.js +37 -20
- package/src/global/paths.js +3 -0
- package/src/global/runtime/alerts/alert-store.js +216 -0
- package/src/global/runtime/alerts/alert-types.js +59 -0
- package/src/global/runtime/alerts/alert-validate.js +117 -0
- package/src/global/runtime/monitor/monitor-cli.js +62 -0
- package/src/global/runtime/monitor/monitor-platform.js +95 -0
- package/src/global/runtime/monitor/monitor.js +249 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated Settings catalog — browse → preview → confirm (no filesystem install).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const SETTINGS_PHASE = Object.freeze({
|
|
6
|
+
BROWSE: "browse",
|
|
7
|
+
PREVIEW: "preview",
|
|
8
|
+
CONFIRMING: "confirming",
|
|
9
|
+
COMPLETED: "completed"
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const CURATED_INTEGRATIONS = Object.freeze([
|
|
13
|
+
Object.freeze({
|
|
14
|
+
id: "pi-usage-widget",
|
|
15
|
+
name: "Pi usage widget",
|
|
16
|
+
version: "0.2.1",
|
|
17
|
+
license: "MIT",
|
|
18
|
+
status: "available",
|
|
19
|
+
capabilities: Object.freeze(["usage-display", "local-only"]),
|
|
20
|
+
permissions: Object.freeze(["full-local-access-on-install"]),
|
|
21
|
+
audit: "pending-security-review",
|
|
22
|
+
summary: "Local Pi package for usage visibility in the agent UI.",
|
|
23
|
+
notes: "Explicit install only. Never auto-applied by Kairo."
|
|
24
|
+
})
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
export function createSettingsActionState() {
|
|
28
|
+
return {
|
|
29
|
+
phase: SETTINGS_PHASE.BROWSE,
|
|
30
|
+
selectedId: null,
|
|
31
|
+
message: null,
|
|
32
|
+
receipt: null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function listCuratedIntegrations() {
|
|
37
|
+
return [...CURATED_INTEGRATIONS];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getCuratedIntegration(id) {
|
|
41
|
+
return CURATED_INTEGRATIONS.find((entry) => entry.id === id) ?? null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function reduceSettingsAction(state, action) {
|
|
45
|
+
switch (action.type) {
|
|
46
|
+
case "reset":
|
|
47
|
+
return createSettingsActionState();
|
|
48
|
+
case "preview": {
|
|
49
|
+
const entry = getCuratedIntegration(action.id);
|
|
50
|
+
if (!entry) {
|
|
51
|
+
return { ...state, phase: SETTINGS_PHASE.BROWSE, message: "Integration not found." };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
phase: SETTINGS_PHASE.PREVIEW,
|
|
55
|
+
selectedId: entry.id,
|
|
56
|
+
message: "Enter Confirm · Esc back — no files written yet.",
|
|
57
|
+
receipt: null
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
case "confirm-prompt":
|
|
61
|
+
if (state.phase !== SETTINGS_PHASE.PREVIEW || !state.selectedId) return state;
|
|
62
|
+
return {
|
|
63
|
+
...state,
|
|
64
|
+
phase: SETTINGS_PHASE.CONFIRMING,
|
|
65
|
+
message: "Confirm explicit install intent? Y confirm · N/Esc cancel"
|
|
66
|
+
};
|
|
67
|
+
case "confirm": {
|
|
68
|
+
if (state.phase !== SETTINGS_PHASE.CONFIRMING || !state.selectedId) return state;
|
|
69
|
+
const entry = getCuratedIntegration(state.selectedId);
|
|
70
|
+
return {
|
|
71
|
+
phase: SETTINGS_PHASE.COMPLETED,
|
|
72
|
+
selectedId: state.selectedId,
|
|
73
|
+
message: "Confirmed — no auto-install. Apply via documented Pi/CLI path only.",
|
|
74
|
+
receipt: {
|
|
75
|
+
id: state.selectedId,
|
|
76
|
+
version: entry?.version ?? null,
|
|
77
|
+
confirmedAt: new Date().toISOString(),
|
|
78
|
+
wroteFiles: false
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
case "cancel":
|
|
83
|
+
return {
|
|
84
|
+
...createSettingsActionState(),
|
|
85
|
+
message: "Cancelled — no files written."
|
|
86
|
+
};
|
|
87
|
+
default:
|
|
88
|
+
return state;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function formatSettingsBrowseLines(
|
|
93
|
+
integrations = listCuratedIntegrations(),
|
|
94
|
+
listIndex = 0
|
|
95
|
+
) {
|
|
96
|
+
if (integrations.length === 0) return ["No curated integrations available."];
|
|
97
|
+
return [
|
|
98
|
+
"CURATED INTEGRATIONS",
|
|
99
|
+
...integrations.map((entry, index) => {
|
|
100
|
+
const mark = index === listIndex ? "›" : " ";
|
|
101
|
+
return `${mark} ${entry.status} · ${entry.name} · ${entry.version} · ${entry.license}`;
|
|
102
|
+
}),
|
|
103
|
+
"",
|
|
104
|
+
"POLICY",
|
|
105
|
+
"Browse → preview → confirm. Install stays explicit; never automatic.",
|
|
106
|
+
"Enter preview · Esc back"
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function formatSettingsDetailLines(entry, settingsAction = null) {
|
|
111
|
+
if (!entry) return ["Integration not found."];
|
|
112
|
+
const phase = settingsAction?.phase ?? SETTINGS_PHASE.BROWSE;
|
|
113
|
+
|
|
114
|
+
// Completed: receipt first so compact TTY (80×24) shows wroteFiles above the fold.
|
|
115
|
+
if (phase === SETTINGS_PHASE.COMPLETED && settingsAction?.receipt) {
|
|
116
|
+
const receipt = settingsAction.receipt;
|
|
117
|
+
return [
|
|
118
|
+
"RESULT",
|
|
119
|
+
settingsAction.message ?? "Confirmed — no auto-install.",
|
|
120
|
+
"RECEIPT",
|
|
121
|
+
`Id · ${receipt.id} · wroteFiles · ${receipt.wroteFiles}`,
|
|
122
|
+
`Confirmed · ${receipt.confirmedAt}`,
|
|
123
|
+
`${entry.name} · ${entry.version} · ${entry.license}`,
|
|
124
|
+
"Esc back · install stays explicit"
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const lines = [
|
|
129
|
+
"INTEGRATION",
|
|
130
|
+
`${entry.name} · ${entry.version}`,
|
|
131
|
+
`Status · ${entry.status} · License · ${entry.license}`,
|
|
132
|
+
`Audit · ${entry.audit}`,
|
|
133
|
+
"",
|
|
134
|
+
"CAPABILITIES",
|
|
135
|
+
entry.capabilities.join(" · ") || "none",
|
|
136
|
+
"",
|
|
137
|
+
"PERMISSIONS",
|
|
138
|
+
entry.permissions.join(" · ") || "none",
|
|
139
|
+
"",
|
|
140
|
+
"SUMMARY",
|
|
141
|
+
entry.summary,
|
|
142
|
+
entry.notes
|
|
143
|
+
];
|
|
144
|
+
if (phase === SETTINGS_PHASE.PREVIEW || phase === SETTINGS_PHASE.CONFIRMING) {
|
|
145
|
+
lines.push("", "PREVIEW", "No filesystem changes. Confirm only records explicit intent.");
|
|
146
|
+
}
|
|
147
|
+
if (settingsAction?.message) lines.push("", settingsAction.message);
|
|
148
|
+
return lines;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function formatSettingsLines({
|
|
152
|
+
listIndex = 0,
|
|
153
|
+
settingsAction = null,
|
|
154
|
+
snapshot = null,
|
|
155
|
+
diagnostics = null
|
|
156
|
+
} = {}) {
|
|
157
|
+
const integrations = listCuratedIntegrations();
|
|
158
|
+
const phase = settingsAction?.phase ?? SETTINGS_PHASE.BROWSE;
|
|
159
|
+
if (phase !== SETTINGS_PHASE.BROWSE && settingsAction?.selectedId) {
|
|
160
|
+
return formatSettingsDetailLines(
|
|
161
|
+
getCuratedIntegration(settingsAction.selectedId),
|
|
162
|
+
settingsAction
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const policy = snapshot?.policy;
|
|
167
|
+
const sources = diagnostics?.profile?.sources;
|
|
168
|
+
const sourceLabel = sources?.global || sources?.project
|
|
169
|
+
? [sources.global ? "global" : null, sources.project ? "project" : null].filter(Boolean).join(", ")
|
|
170
|
+
: "none";
|
|
171
|
+
return [
|
|
172
|
+
...formatSettingsBrowseLines(integrations, listIndex),
|
|
173
|
+
"",
|
|
174
|
+
"PROFILE & POLICY",
|
|
175
|
+
`Policy · ${policy?.profile ?? "none"} · apply ${policy?.applyMode ?? "n/a"}`,
|
|
176
|
+
`Preflight · ${policy?.preflight ?? "n/a"} · sources · ${sourceLabel}`,
|
|
177
|
+
"",
|
|
178
|
+
`Selected · ${integrations[listIndex]?.id ?? "none"}`
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function buildSettingsFooterParts(phase = SETTINGS_PHASE.BROWSE) {
|
|
183
|
+
switch (phase) {
|
|
184
|
+
case SETTINGS_PHASE.PREVIEW:
|
|
185
|
+
return ["Enter Confirm", "Esc Back"];
|
|
186
|
+
case SETTINGS_PHASE.CONFIRMING:
|
|
187
|
+
return ["Y Confirm", "N/Esc Cancel"];
|
|
188
|
+
case SETTINGS_PHASE.COMPLETED:
|
|
189
|
+
return ["Esc Back", "/ Actions"];
|
|
190
|
+
case SETTINGS_PHASE.BROWSE:
|
|
191
|
+
default:
|
|
192
|
+
return ["↑↓ Select", "Enter Preview", "Esc Nav", "/ Actions"];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure Usage / Tokens model — no React/Ink.
|
|
3
|
+
* Shared by formatUsageLines and SemanticUsagePanel.
|
|
4
|
+
*/
|
|
5
|
+
import { LAYOUT_MODES } from "./layout.js";
|
|
6
|
+
|
|
7
|
+
export function usageRunLimit(layoutMode = LAYOUT_MODES.COMPACT) {
|
|
8
|
+
return layoutMode === LAYOUT_MODES.WIDE ? 8 : 3;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function formatMeasuredBudgets(budgets) {
|
|
12
|
+
if (!budgets || typeof budgets !== "object") return null;
|
|
13
|
+
const parts = [];
|
|
14
|
+
if (Number.isFinite(budgets.stableUsedTokens) && Number.isFinite(budgets.stableBudgetTokens)) {
|
|
15
|
+
parts.push(`stable ${budgets.stableUsedTokens}/${budgets.stableBudgetTokens}`);
|
|
16
|
+
}
|
|
17
|
+
if (Number.isFinite(budgets.requestUsedTokens) && Number.isFinite(budgets.requestBudgetTokens)) {
|
|
18
|
+
parts.push(`request ${budgets.requestUsedTokens}/${budgets.requestBudgetTokens}`);
|
|
19
|
+
}
|
|
20
|
+
return parts.length > 0 ? parts.join(" · ") : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolveConfiguredLimits(dashboard) {
|
|
24
|
+
const resolved = dashboard?.profile?.profile ?? {};
|
|
25
|
+
const configured = [];
|
|
26
|
+
if (Number.isFinite(resolved.tokenBudget)) configured.push(`token ${resolved.tokenBudget}`);
|
|
27
|
+
if (Number.isFinite(resolved.stableContextBudget)) configured.push(`stable ${resolved.stableContextBudget}`);
|
|
28
|
+
if (Number.isFinite(resolved.requestContextBudget)) configured.push(`request ${resolved.requestContextBudget}`);
|
|
29
|
+
return configured;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function hasFiniteUsage(usage) {
|
|
33
|
+
if (!usage || typeof usage !== "object") return false;
|
|
34
|
+
return Number.isFinite(usage.total)
|
|
35
|
+
|| Number.isFinite(usage.input)
|
|
36
|
+
|| Number.isFinite(usage.output);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function formatRunUsageLabel(run) {
|
|
40
|
+
const usage = run?.tokenUsage;
|
|
41
|
+
if (!hasFiniteUsage(usage)) return null;
|
|
42
|
+
const parts = [];
|
|
43
|
+
if (Number.isFinite(usage.input)) parts.push(`in ${usage.input}`);
|
|
44
|
+
if (Number.isFinite(usage.output)) parts.push(`out ${usage.output}`);
|
|
45
|
+
if (Number.isFinite(usage.total)) parts.push(`total ${usage.total}`);
|
|
46
|
+
return `${run.agentId ?? "agent"} · ${parts.join(" · ")}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function collectAuditableRuns(dashboard) {
|
|
50
|
+
return [...(dashboard?.activeRuns ?? []), ...(dashboard?.recentRuns ?? [])]
|
|
51
|
+
.filter((run) => hasFiniteUsage(run?.tokenUsage));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Pure adapter: Callout=status · Measured section owns the value. */
|
|
55
|
+
export function adaptUsageModel({
|
|
56
|
+
snapshot = null,
|
|
57
|
+
dashboard = null,
|
|
58
|
+
layoutMode = LAYOUT_MODES.COMPACT
|
|
59
|
+
} = {}) {
|
|
60
|
+
const measured = formatMeasuredBudgets(snapshot?.budgets);
|
|
61
|
+
const configured = resolveConfiguredLimits(dashboard);
|
|
62
|
+
const allRuns = collectAuditableRuns(dashboard);
|
|
63
|
+
const limit = usageRunLimit(layoutMode);
|
|
64
|
+
const visible = allRuns.slice(0, limit);
|
|
65
|
+
const hidden = Math.max(0, allRuns.length - visible.length);
|
|
66
|
+
const hasEvidence = Boolean(measured) || configured.length > 0 || allRuns.length > 0;
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
title: "Usage",
|
|
70
|
+
callout: hasEvidence
|
|
71
|
+
? {
|
|
72
|
+
tone: "info",
|
|
73
|
+
title: "Usage evidence available",
|
|
74
|
+
body: "Budgets and run tokenUsage only — no invented totals."
|
|
75
|
+
}
|
|
76
|
+
: {
|
|
77
|
+
tone: "info",
|
|
78
|
+
title: "Data unavailable",
|
|
79
|
+
body: "No measured budgets, profile limits, or auditable run tokenUsage."
|
|
80
|
+
},
|
|
81
|
+
measured: measured ?? "Data unavailable",
|
|
82
|
+
configured: configured.length > 0
|
|
83
|
+
? configured.join(" · ")
|
|
84
|
+
: "No profile token budgets configured.",
|
|
85
|
+
runs: visible.map((run, i) => ({
|
|
86
|
+
id: `usage-run-${i}`,
|
|
87
|
+
label: formatRunUsageLabel(run)
|
|
88
|
+
})),
|
|
89
|
+
runTotal: allRuns.length,
|
|
90
|
+
runLimit: limit,
|
|
91
|
+
moreLine: hidden > 0 ? `… ${hidden} more` : null,
|
|
92
|
+
hasEvidence,
|
|
93
|
+
footnote: "Auditable budgets only — no invented token savings."
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function formatUsageLinesFromModel(model) {
|
|
98
|
+
const lines = [
|
|
99
|
+
"MEASURED", model.measured, "",
|
|
100
|
+
"CONFIGURED LIMITS", model.configured, "",
|
|
101
|
+
"RUN USAGE"
|
|
102
|
+
];
|
|
103
|
+
if (model.runs.length === 0) {
|
|
104
|
+
lines.push("No auditable run tokenUsage yet.");
|
|
105
|
+
} else {
|
|
106
|
+
for (const item of model.runs) lines.push(item.label);
|
|
107
|
+
if (model.moreLine) lines.push(model.moreLine);
|
|
108
|
+
}
|
|
109
|
+
lines.push("", model.footnote);
|
|
110
|
+
return lines;
|
|
111
|
+
}
|
|
@@ -5,7 +5,6 @@ import { CockpitEmptyState } from "./cockpit/primitives.js";
|
|
|
5
5
|
import {
|
|
6
6
|
formatProviderLines,
|
|
7
7
|
formatRunDetailLines,
|
|
8
|
-
formatRunLines,
|
|
9
8
|
formatSystemHealthLines,
|
|
10
9
|
formatLaunchWizardLines,
|
|
11
10
|
ORCHESTRATOR_VIEWS,
|
|
@@ -13,50 +12,63 @@ import {
|
|
|
13
12
|
} from "./orchestrator-state.js";
|
|
14
13
|
import { windowLinesForLayout } from "./cockpit-models.js";
|
|
15
14
|
import { LAYOUT_MODES } from "./layout.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
15
|
+
import { SemanticOverviewPanel } from "./ux/live-overview.js";
|
|
16
|
+
import { SemanticGovernancePanel } from "./ux/live-governance.js";
|
|
17
|
+
import { SemanticActivityPanel } from "./ux/live-activity.js";
|
|
18
|
+
import { SemanticOrchestrationPanel } from "./ux/live-orchestration.js";
|
|
19
|
+
import { SemanticAlertsPanel } from "./ux/live-alerts.js";
|
|
20
|
+
import { SemanticSettingsPanel } from "./ux/live-settings.js";
|
|
21
|
+
import { SemanticUsagePanel } from "./ux/live-usage.js";
|
|
22
|
+
import { formatReviewDetailLines } from "./cockpit-reviews.js";
|
|
23
|
+
import { listCuratedIntegrations } from "./cockpit-settings.js";
|
|
24
|
+
|
|
25
|
+
export function PalettePanel({ model, colorEnabled = true }) {
|
|
26
|
+
return React.createElement(Box, { flexDirection: "column" },
|
|
27
|
+
React.createElement(Text, {
|
|
28
|
+
bold: true,
|
|
29
|
+
color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
30
|
+
}, model.title),
|
|
31
|
+
React.createElement(Text, { color: COCKPIT_COLORS.muted }, model.hint),
|
|
32
|
+
React.createElement(Text, null, ""),
|
|
33
|
+
...(model.items ?? []).map((item) => React.createElement(Text, {
|
|
34
|
+
key: item.id,
|
|
35
|
+
bold: item.selected,
|
|
36
|
+
color: item.selected && colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
37
|
+
}, `${item.marker} ${item.label}`))
|
|
38
|
+
);
|
|
39
|
+
}
|
|
20
40
|
|
|
21
41
|
export function ControlCenterPanel({ model, colorEnabled = true }) {
|
|
22
|
-
const
|
|
42
|
+
const status = model.status ?? model.health;
|
|
43
|
+
const next = model.nextAction ?? model.cta;
|
|
23
44
|
return React.createElement(Box, { flexDirection: "column" },
|
|
24
45
|
React.createElement(Text, {
|
|
25
46
|
bold: true,
|
|
26
47
|
color: colorEnabled ? COCKPIT_COLORS.secondary : undefined
|
|
27
48
|
}, model.title),
|
|
28
|
-
React.createElement(Text, null, model.purpose),
|
|
29
49
|
React.createElement(Text, null, ""),
|
|
30
50
|
React.createElement(Text, {
|
|
31
51
|
bold: true,
|
|
32
52
|
color: colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
33
|
-
},
|
|
34
|
-
React.createElement(Text, null,
|
|
35
|
-
...(model.coverageLines ?? []).map((line) =>
|
|
36
|
-
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
37
|
-
),
|
|
53
|
+
}, status?.label),
|
|
54
|
+
React.createElement(Text, null, status?.summaryLine),
|
|
38
55
|
React.createElement(Text, null, ""),
|
|
39
|
-
React.createElement(Text, { bold: true },
|
|
56
|
+
React.createElement(Text, { bold: true }, next?.title ?? "NEXT"),
|
|
40
57
|
React.createElement(Text, {
|
|
41
58
|
bold: true,
|
|
42
59
|
color: colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
43
|
-
},
|
|
44
|
-
React.createElement(Text, null,
|
|
45
|
-
React.createElement(Text, { color: COCKPIT_COLORS.muted },
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
),
|
|
52
|
-
model.proposalLines?.length > 0 && React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
53
|
-
React.createElement(Text, { bold: true }, "PROPOSALS"),
|
|
54
|
-
model.proposalLines.map((line) =>
|
|
55
|
-
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
56
|
-
)
|
|
57
|
-
),
|
|
60
|
+
}, next?.actionTitle),
|
|
61
|
+
next?.actionDetail ? React.createElement(Text, null, next.actionDetail) : null,
|
|
62
|
+
React.createElement(Text, { color: COCKPIT_COLORS.muted }, next?.enterHint),
|
|
63
|
+
React.createElement(Text, null, ""),
|
|
64
|
+
React.createElement(Text, { bold: true }, "ACTIVITY"),
|
|
65
|
+
React.createElement(Text, null, model.activity?.headline ?? "Idle"),
|
|
66
|
+
React.createElement(Text, null, ""),
|
|
67
|
+
React.createElement(Text, { bold: true }, "ALERTS"),
|
|
68
|
+
React.createElement(Text, null, model.alerts?.headline ?? "Alert data unavailable"),
|
|
58
69
|
React.createElement(Text, null, ""),
|
|
59
|
-
React.createElement(Text, {
|
|
70
|
+
React.createElement(Text, { bold: true }, "TOKENS"),
|
|
71
|
+
React.createElement(Text, null, model.tokens?.headline ?? "Data unavailable")
|
|
60
72
|
);
|
|
61
73
|
}
|
|
62
74
|
|
|
@@ -72,18 +84,43 @@ export function renderCockpitView({
|
|
|
72
84
|
launchPermissionIndex,
|
|
73
85
|
launchableAgents,
|
|
74
86
|
controlCenter,
|
|
87
|
+
palette = null,
|
|
75
88
|
layoutMode = LAYOUT_MODES.COMPACT,
|
|
76
89
|
selectedRun,
|
|
77
90
|
selectedEvents,
|
|
78
91
|
reviews = [],
|
|
79
92
|
selectedReview = null,
|
|
93
|
+
alerts = [],
|
|
80
94
|
changesAction = null,
|
|
81
95
|
recoveryAction = null,
|
|
82
|
-
|
|
96
|
+
settingsAction = null,
|
|
97
|
+
colorEnabled = true,
|
|
98
|
+
unicode = true,
|
|
99
|
+
overviewDetailsOpen = false,
|
|
100
|
+
governanceDetailsOpen = false,
|
|
101
|
+
activityDetailsOpen = false,
|
|
102
|
+
contentFocused = false,
|
|
103
|
+
homeDir = null
|
|
83
104
|
}) {
|
|
105
|
+
if (palette) {
|
|
106
|
+
return React.createElement(PalettePanel, { model: palette, colorEnabled });
|
|
107
|
+
}
|
|
84
108
|
switch (view) {
|
|
85
109
|
case ORCHESTRATOR_VIEWS.HOME:
|
|
86
|
-
return React.createElement(
|
|
110
|
+
return React.createElement(SemanticOverviewPanel, {
|
|
111
|
+
model: controlCenter,
|
|
112
|
+
detailsOpen: overviewDetailsOpen,
|
|
113
|
+
colorEnabled,
|
|
114
|
+
unicode
|
|
115
|
+
});
|
|
116
|
+
case ORCHESTRATOR_VIEWS.USAGE:
|
|
117
|
+
return React.createElement(SemanticUsagePanel, {
|
|
118
|
+
snapshot,
|
|
119
|
+
dashboard,
|
|
120
|
+
layoutMode,
|
|
121
|
+
colorEnabled,
|
|
122
|
+
unicode
|
|
123
|
+
});
|
|
87
124
|
case ORCHESTRATOR_VIEWS.IDES:
|
|
88
125
|
case ORCHESTRATOR_VIEWS.PROVIDERS:
|
|
89
126
|
return governanceList("IDEs & models", [
|
|
@@ -94,59 +131,54 @@ export function renderCockpitView({
|
|
|
94
131
|
case ORCHESTRATOR_VIEWS.MODULES:
|
|
95
132
|
return governanceList("Harness modules", formatModuleLines(snapshot), layoutMode, colorEnabled);
|
|
96
133
|
case ORCHESTRATOR_VIEWS.CHANGES:
|
|
97
|
-
return
|
|
98
|
-
|
|
99
|
-
|
|
134
|
+
return React.createElement(SemanticGovernancePanel, {
|
|
135
|
+
snapshot,
|
|
136
|
+
changesAction,
|
|
137
|
+
homeDir,
|
|
138
|
+
detailsOpen: governanceDetailsOpen,
|
|
100
139
|
layoutMode,
|
|
101
|
-
colorEnabled
|
|
102
|
-
|
|
140
|
+
colorEnabled,
|
|
141
|
+
unicode
|
|
142
|
+
});
|
|
103
143
|
case ORCHESTRATOR_VIEWS.ACTIVITY:
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
|
|
144
|
+
return React.createElement(SemanticActivityPanel, {
|
|
145
|
+
snapshot,
|
|
146
|
+
recoveryAction,
|
|
147
|
+
dashboard,
|
|
148
|
+
listIndex,
|
|
149
|
+
homeDir,
|
|
150
|
+
detailsOpen: activityDetailsOpen,
|
|
107
151
|
layoutMode,
|
|
108
|
-
|
|
109
|
-
|
|
152
|
+
contentFocused,
|
|
153
|
+
colorEnabled,
|
|
154
|
+
unicode
|
|
155
|
+
});
|
|
110
156
|
case ORCHESTRATOR_VIEWS.PROFILE:
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
return listBlock(
|
|
114
|
-
"Runs",
|
|
115
|
-
formatRunsHubLines(RUNS_HUB_ITEMS),
|
|
157
|
+
return React.createElement(SemanticSettingsPanel, {
|
|
158
|
+
integrations: listCuratedIntegrations(),
|
|
116
159
|
listIndex,
|
|
160
|
+
settingsAction,
|
|
161
|
+
snapshot,
|
|
162
|
+
diagnostics,
|
|
163
|
+
layoutMode,
|
|
164
|
+
contentFocused,
|
|
117
165
|
colorEnabled,
|
|
118
|
-
|
|
119
|
-
);
|
|
166
|
+
unicode
|
|
167
|
+
});
|
|
168
|
+
case ORCHESTRATOR_VIEWS.RUNS:
|
|
120
169
|
case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
|
|
121
|
-
return listBlock(
|
|
122
|
-
"Active runs",
|
|
123
|
-
formatRunLines(dashboard?.activeRuns ?? [], {
|
|
124
|
-
emptyMessage: "No runs executing. Governance first — launch only after setup/repairs.",
|
|
125
|
-
readable: true
|
|
126
|
-
}),
|
|
127
|
-
listIndex,
|
|
128
|
-
colorEnabled,
|
|
129
|
-
"Runs are secondary. Prefer Control center Actions when drift or setup remains."
|
|
130
|
-
);
|
|
131
170
|
case ORCHESTRATOR_VIEWS.RECENT_RUNS:
|
|
132
|
-
return listBlock(
|
|
133
|
-
"Run history",
|
|
134
|
-
formatRunLines(dashboard?.recentRuns ?? [], {
|
|
135
|
-
emptyMessage: "No completed runs yet.",
|
|
136
|
-
readable: true
|
|
137
|
-
}),
|
|
138
|
-
listIndex,
|
|
139
|
-
colorEnabled,
|
|
140
|
-
"Open Runs after governance is healthy."
|
|
141
|
-
);
|
|
142
171
|
case ORCHESTRATOR_VIEWS.REVIEWS:
|
|
143
|
-
return
|
|
144
|
-
|
|
145
|
-
|
|
172
|
+
return React.createElement(SemanticOrchestrationPanel, {
|
|
173
|
+
view,
|
|
174
|
+
dashboard,
|
|
175
|
+
reviews,
|
|
146
176
|
listIndex,
|
|
177
|
+
layoutMode,
|
|
178
|
+
contentFocused,
|
|
147
179
|
colorEnabled,
|
|
148
|
-
|
|
149
|
-
);
|
|
180
|
+
unicode
|
|
181
|
+
});
|
|
150
182
|
case ORCHESTRATOR_VIEWS.LAUNCH:
|
|
151
183
|
if (launchableAgents.length === 0) {
|
|
152
184
|
return React.createElement(CockpitEmptyState, {
|
|
@@ -173,7 +205,7 @@ export function renderCockpitView({
|
|
|
173
205
|
case ORCHESTRATOR_VIEWS.RUN_DETAIL:
|
|
174
206
|
return React.createElement(Box, { flexDirection: "column" },
|
|
175
207
|
React.createElement(Text, { bold: true }, "Run detail"),
|
|
176
|
-
formatRunDetailLines(selectedRun, selectedEvents)
|
|
208
|
+
formatRunDetailLines(selectedRun, selectedEvents, { homeDir })
|
|
177
209
|
.map((line) => React.createElement(Text, { key: line }, line))
|
|
178
210
|
);
|
|
179
211
|
case ORCHESTRATOR_VIEWS.REVIEW_DETAIL:
|
|
@@ -182,6 +214,15 @@ export function renderCockpitView({
|
|
|
182
214
|
formatReviewDetailLines(selectedReview)
|
|
183
215
|
.map((line) => React.createElement(Text, { key: line }, line))
|
|
184
216
|
);
|
|
217
|
+
case ORCHESTRATOR_VIEWS.ALERTS:
|
|
218
|
+
return React.createElement(SemanticAlertsPanel, {
|
|
219
|
+
alerts,
|
|
220
|
+
listIndex,
|
|
221
|
+
layoutMode,
|
|
222
|
+
contentFocused,
|
|
223
|
+
colorEnabled,
|
|
224
|
+
unicode
|
|
225
|
+
});
|
|
185
226
|
case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
|
|
186
227
|
return governanceList(
|
|
187
228
|
"System health",
|
|
@@ -194,8 +235,8 @@ export function renderCockpitView({
|
|
|
194
235
|
React.createElement(Text, { bold: true }, "Help"),
|
|
195
236
|
React.createElement(Text, null, "Kairo keeps IDEs and agents aligned with project architecture and workflows."),
|
|
196
237
|
React.createElement(Text, null, "Primary flow: scan → findings → preview → confirm → apply → re-scan."),
|
|
197
|
-
React.createElement(Text, null, "↑↓ navigate · Enter open · Esc back
|
|
198
|
-
React.createElement(Text, null, "
|
|
238
|
+
React.createElement(Text, null, "↑↓ navigate · Enter open/activate · / actions · Esc back · R refresh · ? help"),
|
|
239
|
+
React.createElement(Text, null, "Overview hides raw diagnostics — Enter opens detail destinations.")
|
|
199
240
|
);
|
|
200
241
|
default: {
|
|
201
242
|
const _exhaustive = view;
|
|
@@ -213,8 +254,8 @@ function governanceList(title, lines, layoutMode, colorEnabled) {
|
|
|
213
254
|
message: "No data yet from the read-only scan.",
|
|
214
255
|
hint: "Press R to rescan."
|
|
215
256
|
})
|
|
216
|
-
: windowed.items.map((line) => React.createElement(Text, {
|
|
217
|
-
key: line
|
|
257
|
+
: windowed.items.map((line, index) => React.createElement(Text, {
|
|
258
|
+
key: `${index}-${line}`,
|
|
218
259
|
color: colorEnabled ? undefined : undefined
|
|
219
260
|
}, line)),
|
|
220
261
|
windowed.moreLine && React.createElement(Text, {
|
|
@@ -239,42 +280,4 @@ function formatModuleLines(snapshot) {
|
|
|
239
280
|
];
|
|
240
281
|
}
|
|
241
282
|
|
|
242
|
-
function formatChangeLines(snapshot, changesAction, layoutMode = LAYOUT_MODES.COMPACT) {
|
|
243
|
-
return formatChangesActionLines({ snapshot, changesAction, layoutMode });
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function formatProfileLines(snapshot, diagnostics) {
|
|
247
|
-
const policy = snapshot?.policy;
|
|
248
|
-
const sources = diagnostics?.profile?.sources;
|
|
249
|
-
const sourceLabel = sources?.global || sources?.project
|
|
250
|
-
? [sources.global ? "global" : null, sources.project ? "project" : null].filter(Boolean).join(", ")
|
|
251
|
-
: "none";
|
|
252
|
-
return [
|
|
253
|
-
`Policy profile: ${policy?.profile ?? "none"}`,
|
|
254
|
-
`Apply mode: ${policy?.applyMode ?? "n/a"}`,
|
|
255
|
-
`Preflight: ${policy?.preflight ?? "n/a"}`,
|
|
256
|
-
`Policy source: ${policy?.source ?? "none"}`,
|
|
257
|
-
`Kairo profile sources: ${sourceLabel}`,
|
|
258
|
-
"",
|
|
259
|
-
"Project overrides global overrides defaults. Consent remains explicit for writes."
|
|
260
|
-
];
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function listBlock(title, lines, listIndex, colorEnabled, emptyHint) {
|
|
264
|
-
const isEmpty = lines.length === 1 && /no |nothing |empty/i.test(lines[0]);
|
|
265
|
-
return React.createElement(Box, { flexDirection: "column" },
|
|
266
|
-
React.createElement(Text, { bold: true }, title),
|
|
267
|
-
isEmpty
|
|
268
|
-
? React.createElement(CockpitEmptyState, {
|
|
269
|
-
message: lines[0],
|
|
270
|
-
hint: emptyHint
|
|
271
|
-
})
|
|
272
|
-
: lines.map((line, index) => React.createElement(Text, {
|
|
273
|
-
key: `${index}-${line}`,
|
|
274
|
-
bold: index === listIndex,
|
|
275
|
-
color: index === listIndex && colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
276
|
-
}, `${index === listIndex ? "› " : " "}${line}`))
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
283
|
export { LAUNCH_WIZARD_STEPS };
|