@kal-elsam/kairo-runtime 0.4.3 → 0.5.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 +124 -17
- package/global-template/components/catalog.json +63 -6
- package/global-template/components/sdd-core/personas/teaching.md +42 -0
- package/global-template/components/sdd-core/skills/sdd-apply/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-apply/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-archive/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-archive/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-design/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-design/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-explore/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-explore/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-init/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-init/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-propose/SKILL.md +35 -0
- package/global-template/components/sdd-core/skills/sdd-propose/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-spec/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-spec/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-tasks/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-tasks/references/contract.md +4 -0
- package/global-template/components/sdd-core/skills/sdd-verify/SKILL.md +34 -0
- package/global-template/components/sdd-core/skills/sdd-verify/references/contract.md +4 -0
- package/package.json +1 -1
- package/scripts/cockpit-smoke.mjs +29 -8
- package/scripts/smoke-test.sh +9 -0
- package/src/cli.js +54 -5
- package/src/global/action-planner.js +17 -4
- package/src/global/component-authoring.js +1 -2
- package/src/global/component-ecosystem-checks.js +74 -15
- package/src/global/component-health.js +56 -0
- package/src/global/component-integration-cli.js +302 -0
- package/src/global/component-manifest.js +214 -0
- package/src/global/component-registry.js +19 -2
- package/src/global/component-resolve.js +51 -0
- package/src/global/components/sdd-core.js +6 -0
- package/src/global/control-plane-proposals.js +229 -0
- package/src/global/control-plane-snapshot.js +212 -0
- package/src/global/dashboard-guidance.js +27 -3
- package/src/global/diff.js +2 -5
- package/src/global/global-cli.js +16 -1
- package/src/global/global-doctor.js +75 -2
- package/src/global/global-installer.js +43 -6
- package/src/global/governance-actions.js +212 -0
- package/src/global/governance-repair.js +13 -0
- package/src/global/ink/cockpit-changes.js +124 -0
- package/src/global/ink/cockpit-control-center.js +106 -0
- package/src/global/ink/cockpit-controller.js +17 -0
- package/src/global/ink/cockpit-enter.js +27 -0
- package/src/global/ink/cockpit-focus.js +7 -1
- package/src/global/ink/cockpit-models.js +98 -46
- package/src/global/ink/cockpit-proposals.js +82 -0
- package/src/global/ink/cockpit-recovery.js +120 -0
- package/src/global/ink/cockpit-runs.js +47 -0
- package/src/global/ink/cockpit-scan.js +60 -0
- package/src/global/ink/cockpit-views.js +144 -74
- package/src/global/ink/orchestrator-app.js +156 -42
- package/src/global/ink/orchestrator-state.js +6 -0
- package/src/global/ink/use-orchestrator-data.js +239 -17
- package/src/global/integrations/engram-apply.js +105 -0
- package/src/global/integrations/engram-evidence.js +218 -0
- package/src/global/integrations/engram-exec.js +107 -0
- package/src/global/integrations/engram-plan.js +60 -0
- package/src/global/integrations/engram-provider.js +22 -0
- package/src/global/integrations/engram-receipts.js +116 -0
- package/src/global/integrations/engram-rollback.js +131 -0
- package/src/global/integrations/index.js +12 -0
- package/src/global/integrations/provider-contract.js +83 -0
- package/src/global/integrations/provider-registry.js +47 -0
- package/src/global/integrations/sdd-apply.js +190 -0
- package/src/global/integrations/sdd-destinations.js +95 -0
- package/src/global/integrations/sdd-evidence.js +89 -0
- package/src/global/integrations/sdd-fs-guard.js +183 -0
- package/src/global/integrations/sdd-lifecycle.js +84 -0
- package/src/global/integrations/sdd-persona.js +71 -0
- package/src/global/integrations/sdd-plan.js +87 -0
- package/src/global/integrations/sdd-provider.js +21 -0
- package/src/global/integrations/sdd-receipts.js +44 -0
- package/src/global/integrations/sdd-rollback.js +269 -0
- package/src/global/integrations/sdd-skill-files.js +61 -0
- package/src/global/integrations/sdd-state.js +175 -0
- package/src/global/integrations/sdd-verify.js +122 -0
- package/src/global/intelligence/backends/opencode-catalog.js +212 -0
- package/src/global/intelligence/backends/opencode-cli.js +247 -0
- package/src/global/intelligence/backends/opencode-evidence.js +129 -0
- package/src/global/intelligence/backends/opencode-http.js +152 -0
- package/src/global/intelligence/backends/opencode-invoke.js +83 -0
- package/src/global/intelligence/backends/opencode-providers.js +67 -0
- package/src/global/intelligence/backends/opencode-runtime.js +242 -0
- package/src/global/intelligence/context-compiler.js +95 -50
- package/src/global/intelligence/index.js +38 -1
- package/src/global/intelligence/orchestrate.js +4 -2
- package/src/global/intelligence/registry.js +62 -6
- package/src/global/intelligence/router.js +188 -70
- package/src/global/intelligence/transport-registry.js +147 -0
- package/src/global/intelligence/types.js +21 -2
- package/src/global/intelligence-cli.js +48 -17
- package/src/global/intelligence-session.js +37 -0
- package/src/global/json-output.js +1 -0
- package/src/global/load-component-catalog.js +10 -28
- package/src/global/load-workspace-component-catalog.js +22 -63
- package/src/global/state-migration.js +21 -1
- package/src/global/state.js +13 -8
- package/src/global/status.js +4 -17
- package/src/global/sync.js +2 -5
|
@@ -13,9 +13,12 @@ import {
|
|
|
13
13
|
} from "./orchestrator-state.js";
|
|
14
14
|
import { windowLinesForLayout } from "./cockpit-models.js";
|
|
15
15
|
import { LAYOUT_MODES } from "./layout.js";
|
|
16
|
+
import { formatRunsHubLines, RUNS_HUB_ITEMS } from "./cockpit-runs.js";
|
|
17
|
+
import { formatChangesActionLines } from "./cockpit-changes.js";
|
|
18
|
+
import { formatRecoveryLines } from "./cockpit-recovery.js";
|
|
16
19
|
|
|
17
|
-
export function
|
|
18
|
-
const
|
|
20
|
+
export function ControlCenterPanel({ model, colorEnabled = true }) {
|
|
21
|
+
const health = model.health;
|
|
19
22
|
return React.createElement(Box, { flexDirection: "column" },
|
|
20
23
|
React.createElement(Text, {
|
|
21
24
|
bold: true,
|
|
@@ -23,40 +26,36 @@ export function HomeMissionPanel({ model, colorEnabled = true }) {
|
|
|
23
26
|
}, model.title),
|
|
24
27
|
React.createElement(Text, null, model.purpose),
|
|
25
28
|
React.createElement(Text, null, ""),
|
|
26
|
-
React.createElement(Box, { flexDirection: "column" },
|
|
27
|
-
React.createElement(Text, {
|
|
28
|
-
bold: true,
|
|
29
|
-
color: colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
30
|
-
}, readiness.headline),
|
|
31
|
-
React.createElement(Text, null, readiness.summaryLine),
|
|
32
|
-
...(readiness.capabilityLines ?? []).map((line) =>
|
|
33
|
-
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
34
|
-
),
|
|
35
|
-
React.createElement(Text, null, "")
|
|
36
|
-
),
|
|
37
|
-
React.createElement(Text, { bold: true }, model.next.title),
|
|
38
29
|
React.createElement(Text, {
|
|
39
30
|
bold: true,
|
|
40
31
|
color: colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
41
|
-
},
|
|
42
|
-
React.createElement(Text, null,
|
|
43
|
-
|
|
32
|
+
}, health.label),
|
|
33
|
+
React.createElement(Text, null, health.summaryLine),
|
|
34
|
+
...(model.coverageLines ?? []).map((line) =>
|
|
35
|
+
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
36
|
+
),
|
|
44
37
|
React.createElement(Text, null, ""),
|
|
45
|
-
React.createElement(Text, { bold: true }, model.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
38
|
+
React.createElement(Text, { bold: true }, model.cta.title),
|
|
39
|
+
React.createElement(Text, {
|
|
40
|
+
bold: true,
|
|
41
|
+
color: colorEnabled ? COCKPIT_COLORS.primary : undefined
|
|
42
|
+
}, model.cta.actionTitle),
|
|
43
|
+
React.createElement(Text, null, model.cta.actionDetail),
|
|
44
|
+
React.createElement(Text, { color: COCKPIT_COLORS.muted }, model.cta.enterHint),
|
|
45
|
+
model.notes?.length > 0 && React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
46
|
+
React.createElement(Text, { bold: true }, "NOTES"),
|
|
47
|
+
model.notes.map((line) =>
|
|
48
|
+
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
49
|
+
)
|
|
50
|
+
),
|
|
51
|
+
model.proposalLines?.length > 0 && React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
52
|
+
React.createElement(Text, { bold: true }, "PROPOSALS"),
|
|
53
|
+
model.proposalLines.map((line) =>
|
|
54
|
+
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
55
|
+
)
|
|
56
|
+
),
|
|
55
57
|
React.createElement(Text, null, ""),
|
|
56
|
-
React.createElement(Text, {
|
|
57
|
-
model.explore.lines.map((line) =>
|
|
58
|
-
React.createElement(Text, { key: line, color: COCKPIT_COLORS.muted }, line)
|
|
59
|
-
)
|
|
58
|
+
React.createElement(Text, { color: COCKPIT_COLORS.muted }, model.runsSecondaryHint)
|
|
60
59
|
);
|
|
61
60
|
}
|
|
62
61
|
|
|
@@ -64,65 +63,85 @@ export function renderCockpitView({
|
|
|
64
63
|
view,
|
|
65
64
|
dashboard,
|
|
66
65
|
diagnostics,
|
|
66
|
+
snapshot,
|
|
67
67
|
listIndex,
|
|
68
68
|
launchStep,
|
|
69
69
|
launchDraft,
|
|
70
70
|
launchAgentIndex,
|
|
71
71
|
launchPermissionIndex,
|
|
72
72
|
launchableAgents,
|
|
73
|
+
controlCenter,
|
|
74
|
+
layoutMode = LAYOUT_MODES.COMPACT,
|
|
73
75
|
selectedRun,
|
|
74
76
|
selectedEvents,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
changesAction = null,
|
|
78
|
+
recoveryAction = null,
|
|
77
79
|
colorEnabled = true
|
|
78
80
|
}) {
|
|
79
81
|
switch (view) {
|
|
80
82
|
case ORCHESTRATOR_VIEWS.HOME:
|
|
81
|
-
return React.createElement(
|
|
83
|
+
return React.createElement(ControlCenterPanel, { model: controlCenter, colorEnabled });
|
|
84
|
+
case ORCHESTRATOR_VIEWS.IDES:
|
|
85
|
+
case ORCHESTRATOR_VIEWS.PROVIDERS:
|
|
86
|
+
return governanceList("IDEs & models", [
|
|
87
|
+
...formatProviderLines(dashboard?.providers ?? snapshot?.runtime?.providers ?? []),
|
|
88
|
+
"",
|
|
89
|
+
"Engram / Graphify appear as external integrations when detected; Kairo does not claim to install them."
|
|
90
|
+
], layoutMode, colorEnabled);
|
|
91
|
+
case ORCHESTRATOR_VIEWS.MODULES:
|
|
92
|
+
return governanceList("Harness modules", formatModuleLines(snapshot), layoutMode, colorEnabled);
|
|
93
|
+
case ORCHESTRATOR_VIEWS.CHANGES:
|
|
94
|
+
return governanceList(
|
|
95
|
+
"Changes",
|
|
96
|
+
formatChangeLines(snapshot, changesAction, layoutMode),
|
|
97
|
+
layoutMode,
|
|
98
|
+
colorEnabled
|
|
99
|
+
);
|
|
100
|
+
case ORCHESTRATOR_VIEWS.ACTIVITY:
|
|
101
|
+
return governanceList(
|
|
102
|
+
"Activity & recovery",
|
|
103
|
+
formatRecoveryLines({ snapshot, recoveryAction, listIndex }),
|
|
104
|
+
layoutMode,
|
|
105
|
+
colorEnabled
|
|
106
|
+
);
|
|
107
|
+
case ORCHESTRATOR_VIEWS.PROFILE:
|
|
108
|
+
return governanceList("Profile & policy", formatProfileLines(snapshot, diagnostics), layoutMode, colorEnabled);
|
|
109
|
+
case ORCHESTRATOR_VIEWS.RUNS:
|
|
110
|
+
return listBlock(
|
|
111
|
+
"Runs",
|
|
112
|
+
formatRunsHubLines(RUNS_HUB_ITEMS),
|
|
113
|
+
listIndex,
|
|
114
|
+
colorEnabled,
|
|
115
|
+
"Choose Active runs, History, or New run."
|
|
116
|
+
);
|
|
82
117
|
case ORCHESTRATOR_VIEWS.ACTIVE_RUNS:
|
|
83
118
|
return listBlock(
|
|
84
|
-
"
|
|
119
|
+
"Active runs",
|
|
85
120
|
formatRunLines(dashboard?.activeRuns ?? [], {
|
|
86
|
-
emptyMessage: "No runs
|
|
121
|
+
emptyMessage: "No runs executing. Governance first — launch only after setup/repairs.",
|
|
87
122
|
readable: true
|
|
88
123
|
}),
|
|
89
124
|
listIndex,
|
|
90
125
|
colorEnabled,
|
|
91
|
-
"
|
|
126
|
+
"Runs are secondary. Prefer Control center Actions when drift or setup remains."
|
|
92
127
|
);
|
|
93
128
|
case ORCHESTRATOR_VIEWS.RECENT_RUNS:
|
|
94
129
|
return listBlock(
|
|
95
|
-
"
|
|
130
|
+
"Run history",
|
|
96
131
|
formatRunLines(dashboard?.recentRuns ?? [], {
|
|
97
|
-
emptyMessage: "No completed runs yet.
|
|
132
|
+
emptyMessage: "No completed runs yet.",
|
|
98
133
|
readable: true
|
|
99
134
|
}),
|
|
100
135
|
listIndex,
|
|
101
136
|
colorEnabled,
|
|
102
|
-
"
|
|
103
|
-
);
|
|
104
|
-
case ORCHESTRATOR_VIEWS.PROVIDERS: {
|
|
105
|
-
const lines = formatProviderLines(dashboard?.providers ?? []);
|
|
106
|
-
const windowed = windowLinesForLayout(lines, layoutMode);
|
|
107
|
-
return React.createElement(Box, { flexDirection: "column" },
|
|
108
|
-
React.createElement(Text, { bold: true }, "Agents"),
|
|
109
|
-
lines.length === 0
|
|
110
|
-
? React.createElement(CockpitEmptyState, {
|
|
111
|
-
message: "No agents detected yet.",
|
|
112
|
-
hint: "Open System health or finish setup, then return here."
|
|
113
|
-
})
|
|
114
|
-
: windowed.items.map((line) => React.createElement(Text, { key: line }, line)),
|
|
115
|
-
windowed.moreLine && React.createElement(Text, {
|
|
116
|
-
color: COCKPIT_COLORS.muted
|
|
117
|
-
}, windowed.moreLine)
|
|
137
|
+
"Open Runs after governance is healthy."
|
|
118
138
|
);
|
|
119
|
-
}
|
|
120
139
|
case ORCHESTRATOR_VIEWS.LAUNCH:
|
|
121
140
|
if (launchableAgents.length === 0) {
|
|
122
141
|
return React.createElement(CockpitEmptyState, {
|
|
123
|
-
title: "
|
|
124
|
-
message: "No executable agents are ready.
|
|
125
|
-
hint: "
|
|
142
|
+
title: "Runs",
|
|
143
|
+
message: "No executable agents are ready.",
|
|
144
|
+
hint: "Return to IDEs & models or Changes first."
|
|
126
145
|
});
|
|
127
146
|
}
|
|
128
147
|
return React.createElement(Box, { flexDirection: "column" },
|
|
@@ -146,25 +165,20 @@ export function renderCockpitView({
|
|
|
146
165
|
formatRunDetailLines(selectedRun, selectedEvents)
|
|
147
166
|
.map((line) => React.createElement(Text, { key: line }, line))
|
|
148
167
|
);
|
|
149
|
-
case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
windowed.moreLine && React.createElement(Text, {
|
|
156
|
-
color: COCKPIT_COLORS.muted
|
|
157
|
-
}, windowed.moreLine)
|
|
168
|
+
case ORCHESTRATOR_VIEWS.DIAGNOSTICS:
|
|
169
|
+
return governanceList(
|
|
170
|
+
"System health",
|
|
171
|
+
formatSystemHealthLines(diagnostics),
|
|
172
|
+
layoutMode,
|
|
173
|
+
colorEnabled
|
|
158
174
|
);
|
|
159
|
-
}
|
|
160
175
|
case ORCHESTRATOR_VIEWS.HELP:
|
|
161
176
|
return React.createElement(Box, { flexDirection: "column" },
|
|
162
177
|
React.createElement(Text, { bold: true }, "Help"),
|
|
163
|
-
React.createElement(Text, null, "Kairo
|
|
164
|
-
React.createElement(Text, null, "
|
|
165
|
-
React.createElement(Text, null, "
|
|
166
|
-
React.createElement(Text, null, "
|
|
167
|
-
React.createElement(Text, null, "Audit trail: ~/.harness/runs/<runId>/")
|
|
178
|
+
React.createElement(Text, null, "Kairo keeps IDEs and agents aligned with project architecture and workflows."),
|
|
179
|
+
React.createElement(Text, null, "Primary flow: scan → findings → preview → confirm → apply → re-scan."),
|
|
180
|
+
React.createElement(Text, null, "↑↓ navigate · Enter open · Esc back/exit · R refresh/retry · ? help"),
|
|
181
|
+
React.createElement(Text, null, "Runs are secondary after setup and repairs.")
|
|
168
182
|
);
|
|
169
183
|
default: {
|
|
170
184
|
const _exhaustive = view;
|
|
@@ -173,6 +187,62 @@ export function renderCockpitView({
|
|
|
173
187
|
}
|
|
174
188
|
}
|
|
175
189
|
|
|
190
|
+
function governanceList(title, lines, layoutMode, colorEnabled) {
|
|
191
|
+
const windowed = windowLinesForLayout(lines, layoutMode);
|
|
192
|
+
return React.createElement(Box, { flexDirection: "column" },
|
|
193
|
+
React.createElement(Text, { bold: true }, title),
|
|
194
|
+
lines.length === 0
|
|
195
|
+
? React.createElement(CockpitEmptyState, {
|
|
196
|
+
message: "No data yet from the read-only scan.",
|
|
197
|
+
hint: "Press R to rescan."
|
|
198
|
+
})
|
|
199
|
+
: windowed.items.map((line) => React.createElement(Text, {
|
|
200
|
+
key: line,
|
|
201
|
+
color: colorEnabled ? undefined : undefined
|
|
202
|
+
}, line)),
|
|
203
|
+
windowed.moreLine && React.createElement(Text, {
|
|
204
|
+
color: COCKPIT_COLORS.muted
|
|
205
|
+
}, windowed.moreLine)
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function formatModuleLines(snapshot) {
|
|
210
|
+
const components = snapshot?.status?.components ?? [];
|
|
211
|
+
if (components.length === 0) {
|
|
212
|
+
return [
|
|
213
|
+
"No harness modules installed yet.",
|
|
214
|
+
"Orchestrator / SDD-TDD appear after setup.",
|
|
215
|
+
"Engram and Graphify are external integrations Kairo can verify, not install."
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
return [
|
|
219
|
+
...components.map((entry) => `${entry.id} · ${entry.status} · ${entry.source} · v${entry.version}`),
|
|
220
|
+
"",
|
|
221
|
+
"External integrations are reported only when detectable on this machine."
|
|
222
|
+
];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function formatChangeLines(snapshot, changesAction, layoutMode = LAYOUT_MODES.COMPACT) {
|
|
226
|
+
return formatChangesActionLines({ snapshot, changesAction, layoutMode });
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function formatProfileLines(snapshot, diagnostics) {
|
|
230
|
+
const policy = snapshot?.policy;
|
|
231
|
+
const sources = diagnostics?.profile?.sources;
|
|
232
|
+
const sourceLabel = sources?.global || sources?.project
|
|
233
|
+
? [sources.global ? "global" : null, sources.project ? "project" : null].filter(Boolean).join(", ")
|
|
234
|
+
: "none";
|
|
235
|
+
return [
|
|
236
|
+
`Policy profile: ${policy?.profile ?? "none"}`,
|
|
237
|
+
`Apply mode: ${policy?.applyMode ?? "n/a"}`,
|
|
238
|
+
`Preflight: ${policy?.preflight ?? "n/a"}`,
|
|
239
|
+
`Policy source: ${policy?.source ?? "none"}`,
|
|
240
|
+
`Kairo profile sources: ${sourceLabel}`,
|
|
241
|
+
"",
|
|
242
|
+
"Project overrides global overrides defaults. Consent remains explicit for writes."
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
|
|
176
246
|
function listBlock(title, lines, listIndex, colorEnabled, emptyHint) {
|
|
177
247
|
const isEmpty = lines.length === 1 && /no |nothing |empty/i.test(lines[0]);
|
|
178
248
|
return React.createElement(Box, { flexDirection: "column" },
|
|
@@ -16,14 +16,17 @@ import {
|
|
|
16
16
|
COCKPIT_NAV,
|
|
17
17
|
COCKPIT_REGIONS,
|
|
18
18
|
buildFooterModel,
|
|
19
|
-
buildHomeMissionModel,
|
|
20
19
|
buildNavModel,
|
|
21
20
|
buildSystemStripModel,
|
|
22
21
|
buildTopBarModel,
|
|
22
|
+
navIndexForView,
|
|
23
23
|
resolveProjectName
|
|
24
24
|
} from "./cockpit-models.js";
|
|
25
|
-
import {
|
|
25
|
+
import { buildControlCenterModel } from "./cockpit-control-center.js";
|
|
26
|
+
import { resolveEnterNavIntent } from "./cockpit-enter.js";
|
|
27
|
+
import { resolveRunsHubItem, RUNS_HUB_ITEMS } from "./cockpit-runs.js";
|
|
26
28
|
import { resolveProjectReadiness } from "../dashboard-guidance.js";
|
|
29
|
+
import { CONTROL_PLANE_HEALTH } from "../control-plane-snapshot.js";
|
|
27
30
|
import { CockpitShell } from "./cockpit/primitives.js";
|
|
28
31
|
import { renderCockpitView } from "./cockpit-views.js";
|
|
29
32
|
import { handleLaunchInput } from "./launch-input.js";
|
|
@@ -32,6 +35,8 @@ import { useOrchestratorData } from "./use-orchestrator-data.js";
|
|
|
32
35
|
import { resolveTerminalCapabilities } from "./terminal-capabilities.js";
|
|
33
36
|
import { COCKPIT_COLORS } from "./theme.js";
|
|
34
37
|
import { LAYOUT_MODES } from "./layout.js";
|
|
38
|
+
import { CHANGES_PHASE } from "./cockpit-changes.js";
|
|
39
|
+
import { RECOVERY_PHASE, listRecoverySnapshots } from "./cockpit-recovery.js";
|
|
35
40
|
|
|
36
41
|
export function OrchestratorApp({
|
|
37
42
|
homeDir,
|
|
@@ -69,16 +74,13 @@ export function OrchestratorApp({
|
|
|
69
74
|
exit();
|
|
70
75
|
};
|
|
71
76
|
|
|
72
|
-
const openDestination = (
|
|
73
|
-
const
|
|
74
|
-
if (!
|
|
75
|
-
if (destination.action === "launch") {
|
|
76
|
-
data.resetLaunchWizard();
|
|
77
|
-
}
|
|
77
|
+
const openDestination = (destinationKey) => {
|
|
78
|
+
const view = resolveCtaDestinationView(destinationKey);
|
|
79
|
+
if (!view) return false;
|
|
78
80
|
dispatch({
|
|
79
81
|
type: "set-view",
|
|
80
|
-
view
|
|
81
|
-
navIndex:
|
|
82
|
+
view,
|
|
83
|
+
navIndex: navIndexForView(view)
|
|
82
84
|
});
|
|
83
85
|
return true;
|
|
84
86
|
};
|
|
@@ -92,10 +94,9 @@ export function OrchestratorApp({
|
|
|
92
94
|
return;
|
|
93
95
|
}
|
|
94
96
|
if (inputKey.toLowerCase() === "r") {
|
|
95
|
-
data.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
97
|
+
if (data.retrying) return;
|
|
98
|
+
// Keep the error screen until success so Esc stays available during retry.
|
|
99
|
+
data.reload({ asRetry: true }).catch(() => {});
|
|
99
100
|
}
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
@@ -103,6 +104,17 @@ export function OrchestratorApp({
|
|
|
103
104
|
if (data.busy) return;
|
|
104
105
|
|
|
105
106
|
if (key.escape) {
|
|
107
|
+
if (ui.view === ORCHESTRATOR_VIEWS.CHANGES
|
|
108
|
+
&& data.changesAction?.phase === CHANGES_PHASE.CONFIRMING) {
|
|
109
|
+
data.cancelChanges();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (ui.view === ORCHESTRATOR_VIEWS.ACTIVITY
|
|
113
|
+
&& data.recoveryAction?.phase === RECOVERY_PHASE.CONFIRMING) {
|
|
114
|
+
data.cancelRecovery();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
106
118
|
if (ui.view === ORCHESTRATOR_VIEWS.LAUNCH && data.launchableAgents.length > 0) {
|
|
107
119
|
const retreated = handleLaunchInput({
|
|
108
120
|
key,
|
|
@@ -140,11 +152,15 @@ export function OrchestratorApp({
|
|
|
140
152
|
return;
|
|
141
153
|
}
|
|
142
154
|
|
|
143
|
-
const listLength = ui.view === ORCHESTRATOR_VIEWS.
|
|
144
|
-
?
|
|
145
|
-
: ui.view === ORCHESTRATOR_VIEWS.
|
|
146
|
-
? (data.dashboard?.
|
|
147
|
-
:
|
|
155
|
+
const listLength = ui.view === ORCHESTRATOR_VIEWS.RUNS
|
|
156
|
+
? RUNS_HUB_ITEMS.length
|
|
157
|
+
: ui.view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
|
|
158
|
+
? (data.dashboard?.activeRuns ?? []).length
|
|
159
|
+
: ui.view === ORCHESTRATOR_VIEWS.RECENT_RUNS
|
|
160
|
+
? (data.dashboard?.recentRuns ?? []).length
|
|
161
|
+
: ui.view === ORCHESTRATOR_VIEWS.ACTIVITY
|
|
162
|
+
? listRecoverySnapshots(data.snapshot).length
|
|
163
|
+
: 0;
|
|
148
164
|
|
|
149
165
|
let routed = null;
|
|
150
166
|
if (key.tab) {
|
|
@@ -162,17 +178,15 @@ export function OrchestratorApp({
|
|
|
162
178
|
if (routed) {
|
|
163
179
|
if (routed.type === "enter-nav") {
|
|
164
180
|
const item = resolveNavAction(ui.navIndex);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
});
|
|
173
|
-
if (openDestination(mission.next)) return;
|
|
181
|
+
const intent = resolveEnterNavIntent({
|
|
182
|
+
currentView: ui.view,
|
|
183
|
+
navItem: item,
|
|
184
|
+
ctaDestination: data.snapshot?.cta?.destination ?? null
|
|
185
|
+
});
|
|
186
|
+
if (intent.kind === "activate-cta") {
|
|
187
|
+
if (openDestination(intent.destination)) return;
|
|
174
188
|
}
|
|
175
|
-
if (
|
|
189
|
+
if (intent.kind === "launch") {
|
|
176
190
|
data.resetLaunchWizard();
|
|
177
191
|
dispatch({
|
|
178
192
|
type: "set-view",
|
|
@@ -207,6 +221,22 @@ export function OrchestratorApp({
|
|
|
207
221
|
}
|
|
208
222
|
}
|
|
209
223
|
|
|
224
|
+
if (ui.region === COCKPIT_REGIONS.CONTENT
|
|
225
|
+
&& ui.view === ORCHESTRATOR_VIEWS.RUNS
|
|
226
|
+
&& key.return) {
|
|
227
|
+
const hubItem = resolveRunsHubItem(ui.listIndex);
|
|
228
|
+
if (!hubItem) return;
|
|
229
|
+
if (hubItem.action === "launch") {
|
|
230
|
+
data.resetLaunchWizard();
|
|
231
|
+
}
|
|
232
|
+
dispatch({
|
|
233
|
+
type: "set-view",
|
|
234
|
+
view: hubItem.view,
|
|
235
|
+
navIndex: navIndexForView(ORCHESTRATOR_VIEWS.RUNS)
|
|
236
|
+
});
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
210
240
|
if (ui.region === COCKPIT_REGIONS.CONTENT
|
|
211
241
|
&& (ui.view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS || ui.view === ORCHESTRATOR_VIEWS.RECENT_RUNS)
|
|
212
242
|
&& key.return) {
|
|
@@ -228,10 +258,53 @@ export function OrchestratorApp({
|
|
|
228
258
|
}
|
|
229
259
|
}
|
|
230
260
|
|
|
261
|
+
if (ui.view === ORCHESTRATOR_VIEWS.CHANGES) {
|
|
262
|
+
const keyName = inputKey.toLowerCase();
|
|
263
|
+
if (keyName === "a") {
|
|
264
|
+
data.previewChanges().then((preview) => {
|
|
265
|
+
if (preview?.setupRequired) openDestination("control-center");
|
|
266
|
+
}).catch(() => {});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (keyName === "y" && data.changesAction?.phase === CHANGES_PHASE.CONFIRMING) {
|
|
270
|
+
data.confirmApplyChanges().then((result) => {
|
|
271
|
+
if (result?.reason === "setup-required") openDestination("control-center");
|
|
272
|
+
}).catch(() => {});
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (keyName === "n") {
|
|
276
|
+
if (data.changesAction?.phase === CHANGES_PHASE.CONFIRMING) data.cancelChanges();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (keyName === "r") {
|
|
280
|
+
data.rescanChanges().catch(() => {});
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (ui.view === ORCHESTRATOR_VIEWS.ACTIVITY) {
|
|
286
|
+
const keyName = inputKey.toLowerCase();
|
|
287
|
+
if (key.return && ui.region === COCKPIT_REGIONS.CONTENT) {
|
|
288
|
+
const entry = listRecoverySnapshots(data.snapshot)[ui.listIndex];
|
|
289
|
+
if (entry?.name) data.previewRecovery(entry.name).catch(() => {});
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (keyName === "y" && data.recoveryAction?.phase === RECOVERY_PHASE.CONFIRMING) {
|
|
293
|
+
data.confirmApplyRecovery().catch(() => {});
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (keyName === "n") {
|
|
297
|
+
if (data.recoveryAction?.phase === RECOVERY_PHASE.CONFIRMING) data.cancelRecovery();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (keyName === "r") {
|
|
301
|
+
data.rescanRecovery().catch(() => {});
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
231
306
|
if (inputKey.toLowerCase() === "r" && ui.view !== ORCHESTRATOR_VIEWS.LAUNCH) {
|
|
232
|
-
data.reload().catch((
|
|
233
|
-
data.setError(reloadError instanceof Error ? reloadError.message : String(reloadError));
|
|
234
|
-
});
|
|
307
|
+
data.reload().catch(() => {});
|
|
235
308
|
}
|
|
236
309
|
});
|
|
237
310
|
|
|
@@ -246,7 +319,8 @@ export function OrchestratorApp({
|
|
|
246
319
|
return React.createElement(Box, { flexDirection: "column" },
|
|
247
320
|
React.createElement(Text, { bold: true, color: COCKPIT_COLORS.danger }, "Runtime error"),
|
|
248
321
|
React.createElement(Text, null, data.error),
|
|
249
|
-
React.createElement(Text, { dimColor: true },
|
|
322
|
+
React.createElement(Text, { dimColor: true },
|
|
323
|
+
data.retrying ? "Retrying read-only scan…" : "R Retry · Esc to exit")
|
|
250
324
|
);
|
|
251
325
|
}
|
|
252
326
|
|
|
@@ -259,13 +333,15 @@ export function OrchestratorApp({
|
|
|
259
333
|
diagnostics: data.diagnostics,
|
|
260
334
|
dashboard: data.dashboard
|
|
261
335
|
});
|
|
262
|
-
const
|
|
336
|
+
const controlCenter = buildControlCenterModel({
|
|
263
337
|
projectName,
|
|
264
|
-
|
|
265
|
-
diagnostics: data.diagnostics,
|
|
266
|
-
dashboard: data.dashboard,
|
|
338
|
+
snapshot: data.snapshot,
|
|
267
339
|
layoutMode: mode
|
|
268
340
|
});
|
|
341
|
+
const systemOnline = data.snapshot
|
|
342
|
+
? data.snapshot.health !== CONTROL_PLANE_HEALTH.NOT_CONFIGURED
|
|
343
|
+
&& data.snapshot.health !== CONTROL_PLANE_HEALTH.CHECK_FAILED
|
|
344
|
+
: readiness.kind !== "needs_setup";
|
|
269
345
|
|
|
270
346
|
return React.createElement(Box, { flexDirection: "column" },
|
|
271
347
|
data.statusMessage && React.createElement(Text, {
|
|
@@ -274,15 +350,18 @@ export function OrchestratorApp({
|
|
|
274
350
|
React.createElement(CockpitShell, {
|
|
275
351
|
topBar: buildTopBarModel({
|
|
276
352
|
projectName,
|
|
277
|
-
systemOnline
|
|
353
|
+
systemOnline,
|
|
278
354
|
unicode
|
|
279
355
|
}),
|
|
280
356
|
footer: buildFooterModel({
|
|
281
357
|
view: ui.view,
|
|
282
358
|
region: ui.region,
|
|
359
|
+
navIndex: ui.navIndex,
|
|
283
360
|
helpOpen: ui.helpOpen,
|
|
284
361
|
canCancel: isRunCancellable(data.selectedRun),
|
|
285
|
-
unicode
|
|
362
|
+
unicode,
|
|
363
|
+
changesPhase: data.changesAction?.phase ?? null,
|
|
364
|
+
recoveryPhase: data.recoveryAction?.phase ?? null
|
|
286
365
|
}),
|
|
287
366
|
layoutMode: mode,
|
|
288
367
|
nav: buildNavModel({
|
|
@@ -291,12 +370,23 @@ export function OrchestratorApp({
|
|
|
291
370
|
focused: ui.region === COCKPIT_REGIONS.NAV || !isContentInteractiveView(ui.view),
|
|
292
371
|
unicode,
|
|
293
372
|
dashboard: data.dashboard,
|
|
294
|
-
diagnostics: data.diagnostics
|
|
373
|
+
diagnostics: data.diagnostics,
|
|
374
|
+
snapshot: data.snapshot
|
|
295
375
|
}),
|
|
296
376
|
system: buildSystemStripModel({
|
|
297
377
|
dashboard: data.dashboard,
|
|
298
378
|
diagnostics: data.diagnostics,
|
|
299
|
-
readiness
|
|
379
|
+
readiness: data.snapshot
|
|
380
|
+
? {
|
|
381
|
+
kind: data.snapshot.health.toLowerCase(),
|
|
382
|
+
label: controlCenter.health.label,
|
|
383
|
+
healthKind: data.snapshot.health === CONTROL_PLANE_HEALTH.HEALTHY
|
|
384
|
+
? "ready"
|
|
385
|
+
: data.snapshot.health === CONTROL_PLANE_HEALTH.CHECK_FAILED
|
|
386
|
+
? "error"
|
|
387
|
+
: "warn"
|
|
388
|
+
}
|
|
389
|
+
: readiness
|
|
300
390
|
}),
|
|
301
391
|
navFocused: ui.region === COCKPIT_REGIONS.NAV,
|
|
302
392
|
contentFocused: ui.region === COCKPIT_REGIONS.CONTENT,
|
|
@@ -307,6 +397,7 @@ export function OrchestratorApp({
|
|
|
307
397
|
view: ui.view,
|
|
308
398
|
dashboard: data.dashboard,
|
|
309
399
|
diagnostics: data.diagnostics,
|
|
400
|
+
snapshot: data.snapshot,
|
|
310
401
|
listIndex: ui.listIndex,
|
|
311
402
|
launchStep: data.launchStep,
|
|
312
403
|
launchDraft: data.launchDraft,
|
|
@@ -315,10 +406,33 @@ export function OrchestratorApp({
|
|
|
315
406
|
launchableAgents: data.launchableAgents,
|
|
316
407
|
selectedRun: data.selectedRun,
|
|
317
408
|
selectedEvents: data.selectedEvents,
|
|
318
|
-
|
|
409
|
+
changesAction: data.changesAction,
|
|
410
|
+
recoveryAction: data.recoveryAction,
|
|
411
|
+
controlCenter,
|
|
319
412
|
layoutMode: mode,
|
|
320
413
|
colorEnabled
|
|
321
414
|
})
|
|
322
415
|
)
|
|
323
416
|
);
|
|
324
417
|
}
|
|
418
|
+
|
|
419
|
+
function resolveCtaDestinationView(destinationKey) {
|
|
420
|
+
switch (destinationKey) {
|
|
421
|
+
case "changes":
|
|
422
|
+
return ORCHESTRATOR_VIEWS.CHANGES;
|
|
423
|
+
case "control-center":
|
|
424
|
+
return ORCHESTRATOR_VIEWS.HOME;
|
|
425
|
+
case "ides":
|
|
426
|
+
return ORCHESTRATOR_VIEWS.IDES;
|
|
427
|
+
case "modules":
|
|
428
|
+
return ORCHESTRATOR_VIEWS.MODULES;
|
|
429
|
+
case "activity":
|
|
430
|
+
return ORCHESTRATOR_VIEWS.ACTIVITY;
|
|
431
|
+
case "profile":
|
|
432
|
+
return ORCHESTRATOR_VIEWS.PROFILE;
|
|
433
|
+
case "runs":
|
|
434
|
+
return ORCHESTRATOR_VIEWS.RUNS;
|
|
435
|
+
default:
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
@@ -13,6 +13,12 @@ export function canUseOrchestratorShell({
|
|
|
13
13
|
|
|
14
14
|
export const ORCHESTRATOR_VIEWS = {
|
|
15
15
|
HOME: "home",
|
|
16
|
+
IDES: "ides",
|
|
17
|
+
MODULES: "modules",
|
|
18
|
+
CHANGES: "changes",
|
|
19
|
+
ACTIVITY: "activity",
|
|
20
|
+
PROFILE: "profile",
|
|
21
|
+
RUNS: "runs",
|
|
16
22
|
ACTIVE_RUNS: "active-runs",
|
|
17
23
|
RECENT_RUNS: "recent-runs",
|
|
18
24
|
RUN_DETAIL: "run-detail",
|