@kal-elsam/kairo-runtime 0.8.0 → 0.9.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 +31 -11
- package/package.json +1 -1
- package/scripts/cockpit-smoke.mjs +4 -4
- package/src/cli.js +24 -1
- package/src/global/global-doctor.js +2 -0
- package/src/global/ink/cockpit/primitives.js +96 -31
- package/src/global/ink/cockpit-alerts.js +36 -0
- package/src/global/ink/cockpit-changes.js +59 -35
- package/src/global/ink/cockpit-control-center.js +129 -51
- package/src/global/ink/cockpit-controller.js +58 -11
- package/src/global/ink/cockpit-focus.js +4 -2
- package/src/global/ink/cockpit-models.js +89 -47
- package/src/global/ink/cockpit-palette.js +98 -0
- package/src/global/ink/cockpit-path-label.js +19 -0
- package/src/global/ink/cockpit-recovery.js +78 -15
- 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-views.js +88 -57
- package/src/global/ink/orchestrator-app.js +137 -46
- package/src/global/ink/orchestrator-state.js +24 -14
- package/src/global/ink/use-orchestrator-data.js +58 -0
- 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
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { CONTROL_PLANE_HEALTH } from "../control-plane-snapshot.js";
|
|
2
|
-
import {
|
|
2
|
+
import { formatAlertsHeadline } from "./cockpit-alerts.js";
|
|
3
3
|
|
|
4
4
|
export function buildControlCenterModel({
|
|
5
5
|
projectName = "project",
|
|
6
6
|
snapshot = null,
|
|
7
|
-
|
|
7
|
+
dashboard = null,
|
|
8
|
+
layoutMode = "compact",
|
|
9
|
+
alerts = null
|
|
8
10
|
} = {}) {
|
|
9
11
|
if (!snapshot) {
|
|
10
12
|
return {
|
|
11
|
-
title: `
|
|
12
|
-
purpose: "
|
|
13
|
+
title: `OVERVIEW — ${projectName}`,
|
|
14
|
+
purpose: "",
|
|
13
15
|
health: {
|
|
14
16
|
kind: CONTROL_PLANE_HEALTH.CHECK_FAILED,
|
|
15
17
|
label: "CHECK FAILED",
|
|
16
18
|
summaryLine: "Control-plane scan not available yet."
|
|
17
19
|
},
|
|
20
|
+
status: {
|
|
21
|
+
kind: CONTROL_PLANE_HEALTH.CHECK_FAILED,
|
|
22
|
+
label: "CHECK FAILED",
|
|
23
|
+
summaryLine: "Control-plane scan not available yet."
|
|
24
|
+
},
|
|
18
25
|
coverageLines: [],
|
|
19
26
|
cta: {
|
|
20
27
|
title: "NEXT",
|
|
@@ -24,54 +31,66 @@ export function buildControlCenterModel({
|
|
|
24
31
|
kind: "verify",
|
|
25
32
|
destination: null
|
|
26
33
|
},
|
|
34
|
+
nextAction: {
|
|
35
|
+
title: "NEXT",
|
|
36
|
+
actionTitle: "Retry scan",
|
|
37
|
+
actionDetail: "Press R to reload the read-only governance scan.",
|
|
38
|
+
enterHint: "R Retry",
|
|
39
|
+
kind: "verify",
|
|
40
|
+
destination: null
|
|
41
|
+
},
|
|
27
42
|
notes: [],
|
|
28
|
-
proposalLines: [
|
|
29
|
-
|
|
43
|
+
proposalLines: [],
|
|
44
|
+
activity: { headline: "No activity yet" },
|
|
45
|
+
alerts: formatAlertsHeadline(alerts),
|
|
46
|
+
tokens: { headline: "Data unavailable" },
|
|
47
|
+
includeEmbeddedStatus: layoutMode !== "wide",
|
|
48
|
+
runsSecondaryHint: "Detail via Enter · / actions"
|
|
30
49
|
};
|
|
31
50
|
}
|
|
32
51
|
|
|
33
52
|
const healthLabel = formatHealthLabel(snapshot.health);
|
|
34
53
|
const coverage = snapshot.coverage ?? {};
|
|
35
|
-
const
|
|
36
|
-
const
|
|
54
|
+
const active = dashboard?.activeRuns?.length ?? snapshot.runtime?.activeRuns ?? 0;
|
|
55
|
+
const recent = dashboard?.recentRuns?.[0] ?? null;
|
|
56
|
+
const health = {
|
|
57
|
+
kind: snapshot.health,
|
|
58
|
+
label: healthLabel,
|
|
59
|
+
summaryLine: [
|
|
60
|
+
`${coverage.governedAgents ?? 0}/${coverage.detectedAgents ?? 0} agents governed`,
|
|
61
|
+
snapshot.diff?.hasChanges ? "drift pending" : "drift clean"
|
|
62
|
+
].join(" · ")
|
|
63
|
+
};
|
|
64
|
+
const cta = {
|
|
65
|
+
title: "NEXT",
|
|
66
|
+
actionTitle: snapshot.cta?.title ?? "Review control plane",
|
|
67
|
+
actionDetail: snapshot.cta?.detail ?? "",
|
|
68
|
+
enterHint: "Enter again →",
|
|
69
|
+
kind: snapshot.cta?.kind ?? null,
|
|
70
|
+
destination: snapshot.cta?.destination ?? null
|
|
71
|
+
};
|
|
37
72
|
|
|
38
73
|
return {
|
|
39
|
-
title: `
|
|
40
|
-
purpose: "
|
|
41
|
-
health
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
? `Notes: ${warnings} non-blocking check warning(s)`
|
|
55
|
-
: "Notes: none",
|
|
56
|
-
snapshot.diff?.hasChanges
|
|
57
|
-
? `Drift: ${snapshot.diff.changeCount ?? snapshot.diff.changes?.length ?? 0} change(s) pending review`
|
|
58
|
-
: "Drift: clean"
|
|
59
|
-
],
|
|
60
|
-
cta: {
|
|
61
|
-
title: "NEXT",
|
|
62
|
-
actionTitle: snapshot.cta?.title ?? "Review control plane",
|
|
63
|
-
actionDetail: snapshot.cta?.detail ?? "",
|
|
64
|
-
enterHint: "Enter again →",
|
|
65
|
-
kind: snapshot.cta?.kind ?? null,
|
|
66
|
-
destination: snapshot.cta?.destination ?? null
|
|
74
|
+
title: `OVERVIEW — ${projectName}`,
|
|
75
|
+
purpose: "",
|
|
76
|
+
health,
|
|
77
|
+
status: health,
|
|
78
|
+
coverageLines: [],
|
|
79
|
+
cta,
|
|
80
|
+
nextAction: cta,
|
|
81
|
+
notes: [],
|
|
82
|
+
proposalLines: [],
|
|
83
|
+
activity: {
|
|
84
|
+
headline: active > 0
|
|
85
|
+
? `${active} active run${active === 1 ? "" : "s"}`
|
|
86
|
+
: recent?.agentId
|
|
87
|
+
? `Last · ${recent.agentId} · ${recent.state ?? "done"}`
|
|
88
|
+
: "Idle"
|
|
67
89
|
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
limit: proposalLimitForLayout(layoutMode),
|
|
71
|
-
budgets: snapshot.budgets ?? null
|
|
72
|
-
}),
|
|
90
|
+
alerts: formatAlertsHeadline(alerts),
|
|
91
|
+
tokens: { headline: formatTokenHeadline(snapshot.budgets) },
|
|
73
92
|
includeEmbeddedStatus: layoutMode !== "wide",
|
|
74
|
-
runsSecondaryHint: "
|
|
93
|
+
runsSecondaryHint: "Detail via Enter · / actions"
|
|
75
94
|
};
|
|
76
95
|
}
|
|
77
96
|
|
|
@@ -92,15 +111,74 @@ function formatHealthLabel(kind) {
|
|
|
92
111
|
}
|
|
93
112
|
}
|
|
94
113
|
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
114
|
+
function formatTokenHeadline(budgets) {
|
|
115
|
+
if (!budgets || typeof budgets !== "object") return "Data unavailable";
|
|
116
|
+
const parts = [];
|
|
117
|
+
if (Number.isFinite(budgets.stableUsedTokens) && Number.isFinite(budgets.stableBudgetTokens)) {
|
|
118
|
+
parts.push(`stable ${budgets.stableUsedTokens}/${budgets.stableBudgetTokens}`);
|
|
101
119
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
120
|
+
if (Number.isFinite(budgets.requestUsedTokens) && Number.isFinite(budgets.requestBudgetTokens)) {
|
|
121
|
+
parts.push(`request ${budgets.requestUsedTokens}/${budgets.requestBudgetTokens}`);
|
|
104
122
|
}
|
|
105
|
-
return
|
|
123
|
+
return parts.length > 0 ? parts.join(" · ") : "Data unavailable";
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Usage surface: measured budgets when present, configured profile limits,
|
|
128
|
+
* and auditable run tokenUsage — never invent totals.
|
|
129
|
+
*/
|
|
130
|
+
function resolveProfileLimits(dashboard) {
|
|
131
|
+
const resolved = dashboard?.profile?.profile ?? {};
|
|
132
|
+
const configured = [];
|
|
133
|
+
if (Number.isFinite(resolved.tokenBudget)) configured.push(`token ${resolved.tokenBudget}`);
|
|
134
|
+
if (Number.isFinite(resolved.stableContextBudget)) configured.push(`stable ${resolved.stableContextBudget}`);
|
|
135
|
+
if (Number.isFinite(resolved.requestContextBudget)) configured.push(`request ${resolved.requestContextBudget}`);
|
|
136
|
+
return configured;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function hasFiniteUsage(usage) {
|
|
140
|
+
if (!usage || typeof usage !== "object") return false;
|
|
141
|
+
return Number.isFinite(usage.total)
|
|
142
|
+
|| Number.isFinite(usage.input)
|
|
143
|
+
|| Number.isFinite(usage.output);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function formatRunUsageLine(run) {
|
|
147
|
+
const usage = run.tokenUsage;
|
|
148
|
+
const parts = [];
|
|
149
|
+
if (Number.isFinite(usage.input)) parts.push(`in ${usage.input}`);
|
|
150
|
+
if (Number.isFinite(usage.output)) parts.push(`out ${usage.output}`);
|
|
151
|
+
if (Number.isFinite(usage.total)) parts.push(`total ${usage.total}`);
|
|
152
|
+
return `${run.agentId ?? "agent"} · ${parts.join(" · ")}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function formatUsageLines({ snapshot = null, dashboard = null } = {}) {
|
|
156
|
+
const lines = ["MEASURED"];
|
|
157
|
+
const measured = formatTokenHeadline(snapshot?.budgets);
|
|
158
|
+
lines.push(measured === "Data unavailable" ? "Data unavailable" : measured);
|
|
159
|
+
|
|
160
|
+
const configured = resolveProfileLimits(dashboard);
|
|
161
|
+
lines.push("", "CONFIGURED LIMITS");
|
|
162
|
+
lines.push(configured.length > 0 ? configured.join(" · ") : "No profile token budgets configured.");
|
|
163
|
+
|
|
164
|
+
const runs = [...(dashboard?.activeRuns ?? []), ...(dashboard?.recentRuns ?? [])]
|
|
165
|
+
.filter((run) => hasFiniteUsage(run?.tokenUsage));
|
|
166
|
+
lines.push("", "RUN USAGE");
|
|
167
|
+
if (runs.length === 0) {
|
|
168
|
+
lines.push("No auditable run tokenUsage yet.");
|
|
169
|
+
} else {
|
|
170
|
+
for (const run of runs.slice(0, 3)) {
|
|
171
|
+
lines.push(formatRunUsageLine(run));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
lines.push("", "Auditable budgets only — no invented token savings.");
|
|
176
|
+
return lines;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function hasAuditableUsage({ snapshot = null, dashboard = null } = {}) {
|
|
180
|
+
if (formatTokenHeadline(snapshot?.budgets) !== "Data unavailable") return true;
|
|
181
|
+
if (resolveProfileLimits(dashboard).length > 0) return true;
|
|
182
|
+
return [...(dashboard?.activeRuns ?? []), ...(dashboard?.recentRuns ?? [])]
|
|
183
|
+
.some((run) => hasFiniteUsage(run?.tokenUsage));
|
|
106
184
|
}
|
|
@@ -33,7 +33,9 @@ export function createCockpitUiState({
|
|
|
33
33
|
navIndex = 0,
|
|
34
34
|
listIndex = 0,
|
|
35
35
|
helpOpen = false,
|
|
36
|
-
returnView = null
|
|
36
|
+
returnView = null,
|
|
37
|
+
paletteOpen = false,
|
|
38
|
+
paletteIndex = 0
|
|
37
39
|
} = {}) {
|
|
38
40
|
const regions = regionsForLayout(layoutMode);
|
|
39
41
|
const preferred = region ?? defaultRegionForView(view, layoutMode);
|
|
@@ -48,12 +50,54 @@ export function createCockpitUiState({
|
|
|
48
50
|
listIndex: Math.max(0, listIndex),
|
|
49
51
|
helpOpen,
|
|
50
52
|
returnView,
|
|
53
|
+
paletteOpen,
|
|
54
|
+
paletteIndex: Math.max(0, paletteIndex),
|
|
51
55
|
shouldExit: false
|
|
52
56
|
};
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
function closePalette(state) {
|
|
60
|
+
return { ...state, paletteOpen: false, paletteIndex: 0 };
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
export function reduceCockpitUi(state, action) {
|
|
56
64
|
switch (action.type) {
|
|
65
|
+
case "toggle-palette":
|
|
66
|
+
if (state.paletteOpen) return closePalette(state);
|
|
67
|
+
return { ...state, paletteOpen: true, paletteIndex: 0, helpOpen: false };
|
|
68
|
+
case "close-palette":
|
|
69
|
+
return closePalette(state);
|
|
70
|
+
case "palette-arrow": {
|
|
71
|
+
const max = Math.max(0, (action.listLength ?? 1) - 1);
|
|
72
|
+
const delta = action.direction === "up" ? -1 : 1;
|
|
73
|
+
return {
|
|
74
|
+
...state,
|
|
75
|
+
paletteIndex: clamp(state.paletteIndex + delta, 0, max)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
case "run-palette": {
|
|
79
|
+
const next = closePalette(state);
|
|
80
|
+
if (action.kind === "help") {
|
|
81
|
+
return {
|
|
82
|
+
...next,
|
|
83
|
+
helpOpen: true,
|
|
84
|
+
view: ORCHESTRATOR_VIEWS.HELP,
|
|
85
|
+
region: defaultRegionForView(ORCHESTRATOR_VIEWS.HELP, state.layoutMode)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (action.kind === "navigate" && action.view) {
|
|
89
|
+
return {
|
|
90
|
+
...next,
|
|
91
|
+
view: action.view,
|
|
92
|
+
navIndex: navIndexForView(action.view),
|
|
93
|
+
listIndex: 0,
|
|
94
|
+
region: defaultRegionForView(action.view, state.layoutMode),
|
|
95
|
+
helpOpen: false,
|
|
96
|
+
returnView: null
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return next;
|
|
100
|
+
}
|
|
57
101
|
case "resize": {
|
|
58
102
|
const regions = regionsForLayout(action.layoutMode);
|
|
59
103
|
const preferred = regions.includes(state.region)
|
|
@@ -95,18 +139,18 @@ export function reduceCockpitUi(state, action) {
|
|
|
95
139
|
case "enter-nav": {
|
|
96
140
|
const item = COCKPIT_NAV[state.navIndex];
|
|
97
141
|
if (!item) return state;
|
|
98
|
-
return {
|
|
142
|
+
return closePalette({
|
|
99
143
|
...state,
|
|
100
144
|
view: item.view,
|
|
101
145
|
listIndex: 0,
|
|
102
146
|
region: defaultRegionForView(item.view, state.layoutMode),
|
|
103
147
|
helpOpen: false,
|
|
104
148
|
returnView: null
|
|
105
|
-
};
|
|
149
|
+
});
|
|
106
150
|
}
|
|
107
151
|
case "set-view": {
|
|
108
152
|
const nextView = action.view;
|
|
109
|
-
return {
|
|
153
|
+
return closePalette({
|
|
110
154
|
...state,
|
|
111
155
|
view: nextView,
|
|
112
156
|
listIndex: 0,
|
|
@@ -116,19 +160,22 @@ export function reduceCockpitUi(state, action) {
|
|
|
116
160
|
region: action.region ?? defaultRegionForView(nextView, state.layoutMode),
|
|
117
161
|
returnView: action.returnView ?? state.returnView,
|
|
118
162
|
helpOpen: nextView === ORCHESTRATOR_VIEWS.HELP
|
|
119
|
-
};
|
|
163
|
+
});
|
|
120
164
|
}
|
|
121
165
|
case "toggle-help":
|
|
122
166
|
if (state.helpOpen || state.view === ORCHESTRATOR_VIEWS.HELP) {
|
|
123
167
|
return goOverview(state);
|
|
124
168
|
}
|
|
125
|
-
return {
|
|
169
|
+
return closePalette({
|
|
126
170
|
...state,
|
|
127
171
|
helpOpen: true,
|
|
128
172
|
view: ORCHESTRATOR_VIEWS.HELP,
|
|
129
173
|
region: defaultRegionForView(ORCHESTRATOR_VIEWS.HELP, state.layoutMode)
|
|
130
|
-
};
|
|
174
|
+
});
|
|
131
175
|
case "escape": {
|
|
176
|
+
if (state.paletteOpen) {
|
|
177
|
+
return closePalette(state);
|
|
178
|
+
}
|
|
132
179
|
if (state.helpOpen || state.view === ORCHESTRATOR_VIEWS.HELP) {
|
|
133
180
|
return goOverview(state);
|
|
134
181
|
}
|
|
@@ -174,7 +221,7 @@ export function resolveNavAction(navIndex) {
|
|
|
174
221
|
}
|
|
175
222
|
|
|
176
223
|
function goOverview(state) {
|
|
177
|
-
return {
|
|
224
|
+
return closePalette({
|
|
178
225
|
...state,
|
|
179
226
|
helpOpen: false,
|
|
180
227
|
view: ORCHESTRATOR_VIEWS.HOME,
|
|
@@ -182,11 +229,11 @@ function goOverview(state) {
|
|
|
182
229
|
listIndex: 0,
|
|
183
230
|
region: defaultRegionForView(ORCHESTRATOR_VIEWS.HOME, state.layoutMode),
|
|
184
231
|
returnView: null
|
|
185
|
-
};
|
|
232
|
+
});
|
|
186
233
|
}
|
|
187
234
|
|
|
188
235
|
function goRunsHub(state) {
|
|
189
|
-
return {
|
|
236
|
+
return closePalette({
|
|
190
237
|
...state,
|
|
191
238
|
helpOpen: false,
|
|
192
239
|
view: ORCHESTRATOR_VIEWS.RUNS,
|
|
@@ -194,5 +241,5 @@ function goRunsHub(state) {
|
|
|
194
241
|
listIndex: 0,
|
|
195
242
|
region: defaultRegionForView(ORCHESTRATOR_VIEWS.RUNS, state.layoutMode),
|
|
196
243
|
returnView: null
|
|
197
|
-
};
|
|
244
|
+
});
|
|
198
245
|
}
|
|
@@ -7,9 +7,9 @@ const NAV_FOCUSED_VIEWS = new Set([
|
|
|
7
7
|
ORCHESTRATOR_VIEWS.IDES,
|
|
8
8
|
ORCHESTRATOR_VIEWS.MODULES,
|
|
9
9
|
ORCHESTRATOR_VIEWS.CHANGES,
|
|
10
|
-
ORCHESTRATOR_VIEWS.PROFILE,
|
|
11
10
|
ORCHESTRATOR_VIEWS.PROVIDERS,
|
|
12
11
|
ORCHESTRATOR_VIEWS.DIAGNOSTICS,
|
|
12
|
+
ORCHESTRATOR_VIEWS.USAGE,
|
|
13
13
|
ORCHESTRATOR_VIEWS.HELP
|
|
14
14
|
]);
|
|
15
15
|
|
|
@@ -20,8 +20,10 @@ const CONTENT_INTERACTIVE_VIEWS = new Set([
|
|
|
20
20
|
ORCHESTRATOR_VIEWS.RUN_DETAIL,
|
|
21
21
|
ORCHESTRATOR_VIEWS.REVIEWS,
|
|
22
22
|
ORCHESTRATOR_VIEWS.REVIEW_DETAIL,
|
|
23
|
+
ORCHESTRATOR_VIEWS.ALERTS,
|
|
23
24
|
ORCHESTRATOR_VIEWS.LAUNCH,
|
|
24
|
-
ORCHESTRATOR_VIEWS.ACTIVITY
|
|
25
|
+
ORCHESTRATOR_VIEWS.ACTIVITY,
|
|
26
|
+
ORCHESTRATOR_VIEWS.PROFILE
|
|
25
27
|
]);
|
|
26
28
|
|
|
27
29
|
export function isNavFocusedView(view) {
|
|
@@ -7,6 +7,7 @@ import { buildHomeMissionModel, formatHomeRecentRun } from "./cockpit-home.js";
|
|
|
7
7
|
import { isRunsBranchView } from "./cockpit-runs.js";
|
|
8
8
|
import { buildChangesFooterParts } from "./cockpit-changes.js";
|
|
9
9
|
import { buildRecoveryFooterParts } from "./cockpit-recovery.js";
|
|
10
|
+
import { buildSettingsFooterParts, SETTINGS_PHASE } from "./cockpit-settings.js";
|
|
10
11
|
|
|
11
12
|
export const COCKPIT_REGIONS = {
|
|
12
13
|
NAV: "nav",
|
|
@@ -17,53 +18,45 @@ export const COCKPIT_REGIONS = {
|
|
|
17
18
|
export const COCKPIT_NAV = [
|
|
18
19
|
{
|
|
19
20
|
id: "overview",
|
|
20
|
-
label: "
|
|
21
|
+
label: "Overview",
|
|
21
22
|
view: ORCHESTRATOR_VIEWS.HOME,
|
|
22
|
-
description: "
|
|
23
|
+
description: "Status, next action, activity, alerts, and tokens."
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
|
-
id: "
|
|
26
|
-
label: "
|
|
27
|
-
view: ORCHESTRATOR_VIEWS.IDES,
|
|
28
|
-
description: "Detected agents, auth signals, capabilities, and recommended policy."
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: "modules",
|
|
32
|
-
label: "Harness modules",
|
|
33
|
-
view: ORCHESTRATOR_VIEWS.MODULES,
|
|
34
|
-
description: "Orchestrator, SDD/TDD, and external Engram/Graphify integrations."
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: "changes",
|
|
38
|
-
label: "Changes",
|
|
26
|
+
id: "governance",
|
|
27
|
+
label: "Governance",
|
|
39
28
|
view: ORCHESTRATOR_VIEWS.CHANGES,
|
|
40
|
-
description: "
|
|
29
|
+
description: "Repair drift and apply governed changes."
|
|
41
30
|
},
|
|
42
31
|
{
|
|
43
32
|
id: "activity",
|
|
44
|
-
label: "Activity
|
|
33
|
+
label: "Activity",
|
|
45
34
|
view: ORCHESTRATOR_VIEWS.ACTIVITY,
|
|
46
|
-
description: "
|
|
35
|
+
description: "Operations, backups, and recovery."
|
|
47
36
|
},
|
|
48
37
|
{
|
|
49
|
-
id: "
|
|
50
|
-
label: "
|
|
51
|
-
view: ORCHESTRATOR_VIEWS.
|
|
52
|
-
description: "
|
|
38
|
+
id: "orchestration",
|
|
39
|
+
label: "Orchestration",
|
|
40
|
+
view: ORCHESTRATOR_VIEWS.RUNS,
|
|
41
|
+
description: "Runs, reviews, and supervised execution."
|
|
53
42
|
},
|
|
54
43
|
{
|
|
55
|
-
id: "
|
|
56
|
-
label: "
|
|
57
|
-
view: ORCHESTRATOR_VIEWS.
|
|
58
|
-
description: "
|
|
44
|
+
id: "usage",
|
|
45
|
+
label: "Usage",
|
|
46
|
+
view: ORCHESTRATOR_VIEWS.USAGE,
|
|
47
|
+
description: "Token and context pressure when auditable."
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "settings",
|
|
51
|
+
label: "Settings",
|
|
52
|
+
view: ORCHESTRATOR_VIEWS.PROFILE,
|
|
53
|
+
description: "Profile, policy, and guided configuration."
|
|
59
54
|
}
|
|
60
55
|
];
|
|
61
56
|
|
|
62
57
|
export function regionsForLayout(layoutMode) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
if (layoutMode === LAYOUT_MODES.COMPACT) {
|
|
58
|
+
// Single main panel: nav strip + content. SYSTEM column retired from the shell.
|
|
59
|
+
if (layoutMode === LAYOUT_MODES.WIDE || layoutMode === LAYOUT_MODES.COMPACT) {
|
|
67
60
|
return [COCKPIT_REGIONS.NAV, COCKPIT_REGIONS.CONTENT];
|
|
68
61
|
}
|
|
69
62
|
return [COCKPIT_REGIONS.CONTENT];
|
|
@@ -71,8 +64,8 @@ export function regionsForLayout(layoutMode) {
|
|
|
71
64
|
|
|
72
65
|
export function navIndexForView(view, items = COCKPIT_NAV) {
|
|
73
66
|
if (isRunsBranchView(view)) {
|
|
74
|
-
const
|
|
75
|
-
return
|
|
67
|
+
const orchIndex = items.findIndex((item) => item.id === "orchestration");
|
|
68
|
+
return orchIndex >= 0 ? orchIndex : 0;
|
|
76
69
|
}
|
|
77
70
|
const index = items.findIndex((item) => item.view === view);
|
|
78
71
|
return index >= 0 ? index : 0;
|
|
@@ -119,18 +112,40 @@ export function resolveNavStatusSummary(item, {
|
|
|
119
112
|
diagnostics,
|
|
120
113
|
dashboard
|
|
121
114
|
}).label;
|
|
115
|
+
case "governance":
|
|
116
|
+
return changes > 0 ? `${changes} pending` : "Clean";
|
|
117
|
+
case "activity":
|
|
118
|
+
return backups > 0 ? `${backups} backups` : "No backups";
|
|
119
|
+
case "orchestration":
|
|
120
|
+
return active === 0 ? "Idle" : `${active} active`;
|
|
121
|
+
case "usage": {
|
|
122
|
+
if (Number.isFinite(snapshot?.budgets?.stableUsedTokens)) return "Auditable";
|
|
123
|
+
const resolved = dashboard?.profile?.profile ?? {};
|
|
124
|
+
if (Number.isFinite(resolved.tokenBudget)
|
|
125
|
+
|| Number.isFinite(resolved.stableContextBudget)
|
|
126
|
+
|| Number.isFinite(resolved.requestContextBudget)) {
|
|
127
|
+
return "Auditable";
|
|
128
|
+
}
|
|
129
|
+
const runs = [...(dashboard?.activeRuns ?? []), ...(dashboard?.recentRuns ?? [])];
|
|
130
|
+
return runs.some((run) => {
|
|
131
|
+
const u = run?.tokenUsage;
|
|
132
|
+
return u && typeof u === "object"
|
|
133
|
+
&& (Number.isFinite(u.total) || Number.isFinite(u.input) || Number.isFinite(u.output));
|
|
134
|
+
})
|
|
135
|
+
? "Auditable"
|
|
136
|
+
: "n/a";
|
|
137
|
+
}
|
|
138
|
+
case "settings":
|
|
139
|
+
return snapshot?.policy?.profile ?? "defaults";
|
|
122
140
|
case "ides":
|
|
123
141
|
return `${governed}/${detected} governed`;
|
|
124
142
|
case "modules":
|
|
125
143
|
return `${snapshot?.coverage?.components ?? 0} modules`;
|
|
126
144
|
case "changes":
|
|
127
145
|
return changes > 0 ? `${changes} pending` : "Clean";
|
|
128
|
-
case "activity":
|
|
129
|
-
return backups > 0 ? `${backups} backups` : "No backups";
|
|
130
146
|
case "profile":
|
|
131
147
|
return snapshot?.policy?.profile ?? "defaults";
|
|
132
148
|
case "runs":
|
|
133
|
-
return active === 0 ? "Idle" : `${active} active`;
|
|
134
149
|
case "active":
|
|
135
150
|
return active === 0 ? "Idle" : `${active} active`;
|
|
136
151
|
case "providers":
|
|
@@ -159,7 +174,7 @@ export function buildNavModel({
|
|
|
159
174
|
const mapped = items.map((item, index) => {
|
|
160
175
|
const isSelected = index === navIndex;
|
|
161
176
|
const isCurrent = item.view === currentView
|
|
162
|
-
|| (item.id === "
|
|
177
|
+
|| (item.id === "orchestration" && isRunsBranchView(currentView));
|
|
163
178
|
return {
|
|
164
179
|
...item,
|
|
165
180
|
marker: isSelected ? glyphs.focus : (isCurrent ? glyphs.bullet : " "),
|
|
@@ -222,45 +237,70 @@ export function buildFooterModel({
|
|
|
222
237
|
region = COCKPIT_REGIONS.NAV,
|
|
223
238
|
navIndex = 0,
|
|
224
239
|
helpOpen = false,
|
|
240
|
+
paletteOpen = false,
|
|
225
241
|
canCancel = false,
|
|
226
242
|
unicode = true,
|
|
227
243
|
hasError = false,
|
|
228
244
|
changesPhase = null,
|
|
229
|
-
recoveryPhase = null
|
|
245
|
+
recoveryPhase = null,
|
|
246
|
+
settingsPhase = null,
|
|
247
|
+
columns = 80
|
|
230
248
|
} = {}) {
|
|
231
249
|
const glyphs = resolveGlyphs(unicode);
|
|
232
250
|
const parts = [];
|
|
251
|
+
const footerColumns = Math.max(24, Math.min(Number(columns) || 80, 120));
|
|
233
252
|
|
|
234
253
|
if (hasError) {
|
|
235
254
|
parts.push("R Retry");
|
|
236
255
|
parts.push("Esc Exit");
|
|
237
|
-
return { text: parts.join(` ${glyphs.bullet} `) };
|
|
256
|
+
return { text: parts.join(` ${glyphs.bullet} `), columns: footerColumns };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (paletteOpen) {
|
|
260
|
+
return {
|
|
261
|
+
text: ["↑↓ Select", "Enter Run", "Esc Close"].join(` ${glyphs.bullet} `),
|
|
262
|
+
columns: footerColumns
|
|
263
|
+
};
|
|
238
264
|
}
|
|
239
265
|
|
|
240
266
|
if (helpOpen || view === ORCHESTRATOR_VIEWS.HELP) {
|
|
241
267
|
parts.push("Esc close help");
|
|
242
268
|
parts.push("? Help");
|
|
243
|
-
return { text: parts.join(` ${glyphs.bullet} `) };
|
|
269
|
+
return { text: parts.join(` ${glyphs.bullet} `), columns: footerColumns };
|
|
244
270
|
}
|
|
245
271
|
|
|
246
272
|
if (view === ORCHESTRATOR_VIEWS.RUN_DETAIL) {
|
|
247
273
|
parts.push("R refresh");
|
|
248
274
|
if (canCancel) parts.push("C cancel");
|
|
249
275
|
parts.push("Esc Back");
|
|
250
|
-
return { text: parts.join(` ${glyphs.bullet} `) };
|
|
276
|
+
return { text: parts.join(` ${glyphs.bullet} `), columns: footerColumns };
|
|
251
277
|
}
|
|
252
278
|
|
|
253
279
|
if (view === ORCHESTRATOR_VIEWS.REVIEW_DETAIL) {
|
|
254
280
|
parts.push("Esc Back");
|
|
255
|
-
return { text: parts.join(` ${glyphs.bullet} `) };
|
|
281
|
+
return { text: parts.join(` ${glyphs.bullet} `), columns: footerColumns };
|
|
256
282
|
}
|
|
257
283
|
|
|
258
284
|
if (view === ORCHESTRATOR_VIEWS.CHANGES) {
|
|
259
|
-
return {
|
|
285
|
+
return {
|
|
286
|
+
text: buildChangesFooterParts(changesPhase).join(` ${glyphs.bullet} `),
|
|
287
|
+
columns: footerColumns
|
|
288
|
+
};
|
|
260
289
|
}
|
|
261
290
|
|
|
262
291
|
if (view === ORCHESTRATOR_VIEWS.ACTIVITY) {
|
|
263
|
-
return {
|
|
292
|
+
return {
|
|
293
|
+
text: buildRecoveryFooterParts(recoveryPhase).join(` ${glyphs.bullet} `),
|
|
294
|
+
columns: footerColumns
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (view === ORCHESTRATOR_VIEWS.PROFILE) {
|
|
299
|
+
return {
|
|
300
|
+
text: buildSettingsFooterParts(settingsPhase ?? SETTINGS_PHASE.BROWSE)
|
|
301
|
+
.join(` ${glyphs.bullet} `),
|
|
302
|
+
columns: footerColumns
|
|
303
|
+
};
|
|
264
304
|
}
|
|
265
305
|
|
|
266
306
|
parts.push("↑↓ Navigate");
|
|
@@ -275,14 +315,15 @@ export function buildFooterModel({
|
|
|
275
315
|
parts.push("Tab Region");
|
|
276
316
|
}
|
|
277
317
|
|
|
278
|
-
const
|
|
279
|
-
if (
|
|
318
|
+
const activatesOverviewCta = view === ORCHESTRATOR_VIEWS.HOME && navIndex === 0;
|
|
319
|
+
if (activatesOverviewCta) {
|
|
280
320
|
parts.push("Enter Activate");
|
|
281
321
|
} else if (view === ORCHESTRATOR_VIEWS.IDES
|
|
282
322
|
|| view === ORCHESTRATOR_VIEWS.MODULES
|
|
283
323
|
|| view === ORCHESTRATOR_VIEWS.PROFILE
|
|
284
324
|
|| view === ORCHESTRATOR_VIEWS.PROVIDERS
|
|
285
325
|
|| view === ORCHESTRATOR_VIEWS.DIAGNOSTICS
|
|
326
|
+
|| view === ORCHESTRATOR_VIEWS.USAGE
|
|
286
327
|
|| region === COCKPIT_REGIONS.NAV
|
|
287
328
|
|| view === ORCHESTRATOR_VIEWS.RUNS
|
|
288
329
|
|| view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
|
|
@@ -295,9 +336,10 @@ export function buildFooterModel({
|
|
|
295
336
|
}
|
|
296
337
|
|
|
297
338
|
parts.push("? Help");
|
|
339
|
+
parts.push("/ Actions");
|
|
298
340
|
parts.push(view === ORCHESTRATOR_VIEWS.HOME ? "Esc Exit" : "Esc Back");
|
|
299
341
|
|
|
300
|
-
return { text: parts.join(` ${glyphs.bullet} `) };
|
|
342
|
+
return { text: parts.join(` ${glyphs.bullet} `), columns: footerColumns };
|
|
301
343
|
}
|
|
302
344
|
|
|
303
345
|
export function windowLinesForLayout(lines = [], layoutMode = LAYOUT_MODES.COMPACT, contentRows = 12) {
|