@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
|
@@ -4,6 +4,9 @@ import { resolveProjectReadiness } from "../dashboard-guidance.js";
|
|
|
4
4
|
import { STATUS_LABELS, resolveGlyphs } from "./theme.js";
|
|
5
5
|
import { windowList } from "./list-window.js";
|
|
6
6
|
import { buildHomeMissionModel, formatHomeRecentRun } from "./cockpit-home.js";
|
|
7
|
+
import { isRunsBranchView } from "./cockpit-runs.js";
|
|
8
|
+
import { buildChangesFooterParts } from "./cockpit-changes.js";
|
|
9
|
+
import { buildRecoveryFooterParts } from "./cockpit-recovery.js";
|
|
7
10
|
|
|
8
11
|
export const COCKPIT_REGIONS = {
|
|
9
12
|
NAV: "nav",
|
|
@@ -14,40 +17,45 @@ export const COCKPIT_REGIONS = {
|
|
|
14
17
|
export const COCKPIT_NAV = [
|
|
15
18
|
{
|
|
16
19
|
id: "overview",
|
|
17
|
-
label: "
|
|
20
|
+
label: "Control center",
|
|
18
21
|
view: ORCHESTRATOR_VIEWS.HOME,
|
|
19
|
-
description: "
|
|
22
|
+
description: "Coverage, integrity, and the next governance action."
|
|
20
23
|
},
|
|
21
24
|
{
|
|
22
|
-
id: "
|
|
23
|
-
label: "
|
|
24
|
-
view: ORCHESTRATOR_VIEWS.
|
|
25
|
-
description: "
|
|
25
|
+
id: "ides",
|
|
26
|
+
label: "IDEs & models",
|
|
27
|
+
view: ORCHESTRATOR_VIEWS.IDES,
|
|
28
|
+
description: "Detected agents, auth signals, capabilities, and recommended policy."
|
|
26
29
|
},
|
|
27
30
|
{
|
|
28
|
-
id: "
|
|
29
|
-
label: "
|
|
30
|
-
view: ORCHESTRATOR_VIEWS.
|
|
31
|
-
description: "
|
|
31
|
+
id: "modules",
|
|
32
|
+
label: "Harness modules",
|
|
33
|
+
view: ORCHESTRATOR_VIEWS.MODULES,
|
|
34
|
+
description: "Orchestrator, SDD/TDD, and external Engram/Graphify integrations."
|
|
32
35
|
},
|
|
33
36
|
{
|
|
34
|
-
id: "
|
|
35
|
-
label: "
|
|
36
|
-
view: ORCHESTRATOR_VIEWS.
|
|
37
|
-
description: "
|
|
37
|
+
id: "changes",
|
|
38
|
+
label: "Changes",
|
|
39
|
+
view: ORCHESTRATOR_VIEWS.CHANGES,
|
|
40
|
+
description: "Findings, drift, and exact preview before any write."
|
|
38
41
|
},
|
|
39
42
|
{
|
|
40
|
-
id: "
|
|
41
|
-
label: "
|
|
42
|
-
view: ORCHESTRATOR_VIEWS.
|
|
43
|
-
|
|
44
|
-
description: "Delegate a task to an executable agent."
|
|
43
|
+
id: "activity",
|
|
44
|
+
label: "Activity & recovery",
|
|
45
|
+
view: ORCHESTRATOR_VIEWS.ACTIVITY,
|
|
46
|
+
description: "Kairo operations, backups, and rollback readiness."
|
|
45
47
|
},
|
|
46
48
|
{
|
|
47
|
-
id: "
|
|
48
|
-
label: "
|
|
49
|
-
view: ORCHESTRATOR_VIEWS.
|
|
50
|
-
description: "
|
|
49
|
+
id: "profile",
|
|
50
|
+
label: "Profile & policy",
|
|
51
|
+
view: ORCHESTRATOR_VIEWS.PROFILE,
|
|
52
|
+
description: "Defaults, scopes, consent, and precedence."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "runs",
|
|
56
|
+
label: "Runs",
|
|
57
|
+
view: ORCHESTRATOR_VIEWS.RUNS,
|
|
58
|
+
description: "Optional supervised execution — Active, History, and New run."
|
|
51
59
|
}
|
|
52
60
|
];
|
|
53
61
|
|
|
@@ -62,6 +70,10 @@ export function regionsForLayout(layoutMode) {
|
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
export function navIndexForView(view, items = COCKPIT_NAV) {
|
|
73
|
+
if (isRunsBranchView(view)) {
|
|
74
|
+
const runsIndex = items.findIndex((item) => item.id === "runs");
|
|
75
|
+
return runsIndex >= 0 ? runsIndex : 0;
|
|
76
|
+
}
|
|
65
77
|
const index = items.findIndex((item) => item.view === view);
|
|
66
78
|
return index >= 0 ? index : 0;
|
|
67
79
|
}
|
|
@@ -82,31 +94,51 @@ export function buildTopBarModel({
|
|
|
82
94
|
};
|
|
83
95
|
}
|
|
84
96
|
|
|
85
|
-
export function resolveNavStatusSummary(item, {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
export function resolveNavStatusSummary(item, {
|
|
98
|
+
dashboard = null,
|
|
99
|
+
diagnostics = null,
|
|
100
|
+
snapshot = null
|
|
101
|
+
} = {}) {
|
|
102
|
+
const active = dashboard?.activeRuns?.length ?? snapshot?.runtime?.activeRuns ?? 0;
|
|
103
|
+
const providers = dashboard?.providers ?? snapshot?.runtime?.providers ?? [];
|
|
89
104
|
const launchable = providers.filter((entry) => entry.launchable).length;
|
|
90
|
-
const detected =
|
|
91
|
-
|
|
105
|
+
const detected = snapshot?.coverage?.detectedAgents
|
|
106
|
+
?? diagnostics?.diagnostics?.detected
|
|
107
|
+
?? providers.filter((p) => p.available).length;
|
|
108
|
+
const governed = snapshot?.coverage?.governedAgents ?? 0;
|
|
109
|
+
const changes = snapshot?.diff?.hasChanges
|
|
110
|
+
? (snapshot.diff.changeCount ?? snapshot.diff.changes?.length ?? 0)
|
|
111
|
+
: 0;
|
|
112
|
+
const backups = snapshot?.backups?.count ?? 0;
|
|
92
113
|
|
|
93
114
|
switch (item.id) {
|
|
94
115
|
case "overview":
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
return snapshot?.health?.replaceAll("_", " ")
|
|
117
|
+
?? resolveProjectReadiness({
|
|
118
|
+
hasGlobalState: true,
|
|
119
|
+
diagnostics,
|
|
120
|
+
dashboard
|
|
121
|
+
}).label;
|
|
122
|
+
case "ides":
|
|
123
|
+
return `${governed}/${detected} governed`;
|
|
124
|
+
case "modules":
|
|
125
|
+
return `${snapshot?.coverage?.components ?? 0} modules`;
|
|
126
|
+
case "changes":
|
|
127
|
+
return changes > 0 ? `${changes} pending` : "Clean";
|
|
128
|
+
case "activity":
|
|
129
|
+
return backups > 0 ? `${backups} backups` : "No backups";
|
|
130
|
+
case "profile":
|
|
131
|
+
return snapshot?.policy?.profile ?? "defaults";
|
|
132
|
+
case "runs":
|
|
133
|
+
return active === 0 ? "Idle" : `${active} active`;
|
|
100
134
|
case "active":
|
|
101
135
|
return active === 0 ? "Idle" : `${active} active`;
|
|
102
|
-
case "recent":
|
|
103
|
-
return recent === 0 ? "No history" : `${recent} recent`;
|
|
104
136
|
case "providers":
|
|
105
137
|
return `${launchable}/${providers.length || detected} ready`;
|
|
106
138
|
case "launch":
|
|
107
139
|
return launchable > 0 ? "Ready" : "Unavailable";
|
|
108
140
|
case "diagnostics":
|
|
109
|
-
return
|
|
141
|
+
return changes > 0 ? `${changes} pending` : "Checked";
|
|
110
142
|
default:
|
|
111
143
|
return "";
|
|
112
144
|
}
|
|
@@ -119,27 +151,29 @@ export function buildNavModel({
|
|
|
119
151
|
unicode = true,
|
|
120
152
|
items = COCKPIT_NAV,
|
|
121
153
|
dashboard = null,
|
|
122
|
-
diagnostics = null
|
|
154
|
+
diagnostics = null,
|
|
155
|
+
snapshot = null
|
|
123
156
|
} = {}) {
|
|
124
157
|
const glyphs = resolveGlyphs(unicode);
|
|
125
158
|
const selected = items[navIndex] ?? items[0];
|
|
126
159
|
const mapped = items.map((item, index) => {
|
|
127
160
|
const isSelected = index === navIndex;
|
|
128
|
-
const isCurrent = item.view === currentView
|
|
161
|
+
const isCurrent = item.view === currentView
|
|
162
|
+
|| (item.id === "runs" && isRunsBranchView(currentView));
|
|
129
163
|
return {
|
|
130
164
|
...item,
|
|
131
165
|
marker: isSelected ? glyphs.focus : (isCurrent ? glyphs.bullet : " "),
|
|
132
166
|
selected: isSelected,
|
|
133
167
|
current: isCurrent,
|
|
134
168
|
focused: focused && isSelected,
|
|
135
|
-
statusSummary: resolveNavStatusSummary(item, { dashboard, diagnostics })
|
|
169
|
+
statusSummary: resolveNavStatusSummary(item, { dashboard, diagnostics, snapshot })
|
|
136
170
|
};
|
|
137
171
|
});
|
|
138
172
|
|
|
139
173
|
return {
|
|
140
174
|
title: "NAVIGATION",
|
|
141
175
|
explanation: selected
|
|
142
|
-
? `${selected.description} (${resolveNavStatusSummary(selected, { dashboard, diagnostics })})`
|
|
176
|
+
? `${selected.description} (${resolveNavStatusSummary(selected, { dashboard, diagnostics, snapshot })})`
|
|
143
177
|
: "",
|
|
144
178
|
items: mapped
|
|
145
179
|
};
|
|
@@ -186,10 +220,13 @@ export function buildSystemStripModel({
|
|
|
186
220
|
export function buildFooterModel({
|
|
187
221
|
view = ORCHESTRATOR_VIEWS.HOME,
|
|
188
222
|
region = COCKPIT_REGIONS.NAV,
|
|
223
|
+
navIndex = 0,
|
|
189
224
|
helpOpen = false,
|
|
190
225
|
canCancel = false,
|
|
191
226
|
unicode = true,
|
|
192
|
-
hasError = false
|
|
227
|
+
hasError = false,
|
|
228
|
+
changesPhase = null,
|
|
229
|
+
recoveryPhase = null
|
|
193
230
|
} = {}) {
|
|
194
231
|
const glyphs = resolveGlyphs(unicode);
|
|
195
232
|
const parts = [];
|
|
@@ -213,24 +250,39 @@ export function buildFooterModel({
|
|
|
213
250
|
return { text: parts.join(` ${glyphs.bullet} `) };
|
|
214
251
|
}
|
|
215
252
|
|
|
253
|
+
if (view === ORCHESTRATOR_VIEWS.CHANGES) {
|
|
254
|
+
return { text: buildChangesFooterParts(changesPhase).join(` ${glyphs.bullet} `) };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (view === ORCHESTRATOR_VIEWS.ACTIVITY) {
|
|
258
|
+
return { text: buildRecoveryFooterParts(recoveryPhase).join(` ${glyphs.bullet} `) };
|
|
259
|
+
}
|
|
260
|
+
|
|
216
261
|
parts.push("↑↓ Navigate");
|
|
217
262
|
|
|
218
|
-
const showTab = view === ORCHESTRATOR_VIEWS.
|
|
263
|
+
const showTab = view === ORCHESTRATOR_VIEWS.RUNS
|
|
264
|
+
|| view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
|
|
219
265
|
|| view === ORCHESTRATOR_VIEWS.RECENT_RUNS
|
|
220
|
-
|| view === ORCHESTRATOR_VIEWS.LAUNCH
|
|
266
|
+
|| view === ORCHESTRATOR_VIEWS.LAUNCH
|
|
267
|
+
|| view === ORCHESTRATOR_VIEWS.ACTIVITY;
|
|
221
268
|
if (showTab) {
|
|
222
269
|
parts.push("Tab Region");
|
|
223
270
|
}
|
|
224
271
|
|
|
225
|
-
|
|
272
|
+
const activatesControlCenterCta = view === ORCHESTRATOR_VIEWS.HOME && navIndex === 0;
|
|
273
|
+
if (activatesControlCenterCta) {
|
|
274
|
+
parts.push("Enter Activate");
|
|
275
|
+
} else if (view === ORCHESTRATOR_VIEWS.IDES
|
|
276
|
+
|| view === ORCHESTRATOR_VIEWS.MODULES
|
|
277
|
+
|| view === ORCHESTRATOR_VIEWS.PROFILE
|
|
226
278
|
|| view === ORCHESTRATOR_VIEWS.PROVIDERS
|
|
227
279
|
|| view === ORCHESTRATOR_VIEWS.DIAGNOSTICS
|
|
228
280
|
|| region === COCKPIT_REGIONS.NAV
|
|
281
|
+
|| view === ORCHESTRATOR_VIEWS.RUNS
|
|
229
282
|
|| view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
|
|
230
283
|
|| view === ORCHESTRATOR_VIEWS.RECENT_RUNS) {
|
|
231
284
|
parts.push("Enter Open");
|
|
232
285
|
}
|
|
233
|
-
|
|
234
286
|
if (view !== ORCHESTRATOR_VIEWS.LAUNCH) {
|
|
235
287
|
parts.push("R refresh");
|
|
236
288
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only proposal presentation for Control Center / Changes.
|
|
3
|
+
* Links to existing views only — never executes actions.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function formatProposalLines(proposals = [], {
|
|
7
|
+
limit = 6,
|
|
8
|
+
destinationFilter = null,
|
|
9
|
+
budgets = null
|
|
10
|
+
} = {}) {
|
|
11
|
+
const filtered = (proposals ?? []).filter((entry) => {
|
|
12
|
+
if (!entry?.id || !entry?.title) return false;
|
|
13
|
+
if (!destinationFilter) return true;
|
|
14
|
+
return entry.destination === destinationFilter;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
if (filtered.length === 0) {
|
|
18
|
+
return destinationFilter
|
|
19
|
+
? ["No proposals targeting this view."]
|
|
20
|
+
: ["No evidence-backed proposals."];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const shown = filtered.slice(0, Math.max(1, limit));
|
|
24
|
+
const lines = [
|
|
25
|
+
`Proposals · ${shown.length}/${filtered.length} evidence-backed`
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const budgetLine = formatProposalBudgetLine(budgets);
|
|
29
|
+
if (budgetLine) lines.push(budgetLine);
|
|
30
|
+
|
|
31
|
+
for (const proposal of shown) {
|
|
32
|
+
const severity = String(proposal.severity ?? "info").toUpperCase();
|
|
33
|
+
const destination = proposal.destination ?? "control-center";
|
|
34
|
+
lines.push(`[${severity}] ${proposal.title} → ${destination}`);
|
|
35
|
+
const evidence = formatProposalEvidenceSource(proposal.evidence);
|
|
36
|
+
if (evidence) lines.push(` evidence: ${evidence}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (filtered.length > shown.length) {
|
|
40
|
+
lines.push(`… ${filtered.length - shown.length} more (open destination views)`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return lines;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function formatProposalEvidenceSource(evidence = []) {
|
|
47
|
+
const sources = [];
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
for (const item of evidence ?? []) {
|
|
50
|
+
const source = String(item?.source ?? "").trim();
|
|
51
|
+
if (!source || seen.has(source)) continue;
|
|
52
|
+
seen.add(source);
|
|
53
|
+
sources.push(source);
|
|
54
|
+
if (sources.length >= 3) break;
|
|
55
|
+
}
|
|
56
|
+
return sources.join(" · ") || null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function formatProposalBudgetLine(budgets) {
|
|
60
|
+
if (!budgets || typeof budgets !== "object") return null;
|
|
61
|
+
const parts = [];
|
|
62
|
+
if (Number.isFinite(budgets.stableUsedTokens) && Number.isFinite(budgets.stableBudgetTokens)) {
|
|
63
|
+
parts.push(`stable ${budgets.stableUsedTokens}/${budgets.stableBudgetTokens}`);
|
|
64
|
+
}
|
|
65
|
+
if (Number.isFinite(budgets.requestUsedTokens) && Number.isFinite(budgets.requestBudgetTokens)) {
|
|
66
|
+
parts.push(`request ${budgets.requestUsedTokens}/${budgets.requestBudgetTokens}`);
|
|
67
|
+
}
|
|
68
|
+
if (parts.length === 0) return null;
|
|
69
|
+
return `Budget · ${parts.join(" · ")}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function proposalLimitForLayout(layoutMode = "compact") {
|
|
73
|
+
switch (layoutMode) {
|
|
74
|
+
case "wide":
|
|
75
|
+
return 6;
|
|
76
|
+
case "minimal":
|
|
77
|
+
return 3;
|
|
78
|
+
case "compact":
|
|
79
|
+
default:
|
|
80
|
+
return 4;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export const RECOVERY_PHASE = Object.freeze({
|
|
2
|
+
IDLE: "idle",
|
|
3
|
+
PREVIEWING: "previewing",
|
|
4
|
+
CONFIRMING: "confirming",
|
|
5
|
+
APPLYING: "applying",
|
|
6
|
+
COMPLETED: "completed",
|
|
7
|
+
FAILED: "failed"
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export function createRecoveryActionState() {
|
|
11
|
+
return {
|
|
12
|
+
phase: RECOVERY_PHASE.IDLE,
|
|
13
|
+
preview: null,
|
|
14
|
+
receipt: null,
|
|
15
|
+
error: null,
|
|
16
|
+
message: null,
|
|
17
|
+
selectedSnapshot: null
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function reduceRecoveryAction(state, action) {
|
|
22
|
+
switch (action.type) {
|
|
23
|
+
case "reset":
|
|
24
|
+
return createRecoveryActionState();
|
|
25
|
+
case "preview-start":
|
|
26
|
+
return {
|
|
27
|
+
...createRecoveryActionState(),
|
|
28
|
+
phase: RECOVERY_PHASE.PREVIEWING,
|
|
29
|
+
selectedSnapshot: action.snapshot ?? null,
|
|
30
|
+
message: `Previewing rollback · ${action.snapshot ?? "?"}`
|
|
31
|
+
};
|
|
32
|
+
case "preview-ready":
|
|
33
|
+
return {
|
|
34
|
+
phase: RECOVERY_PHASE.CONFIRMING,
|
|
35
|
+
preview: action.preview,
|
|
36
|
+
receipt: null,
|
|
37
|
+
error: null,
|
|
38
|
+
selectedSnapshot: action.preview?.snapshot ?? state.selectedSnapshot,
|
|
39
|
+
message: action.preview?.noop
|
|
40
|
+
? "Snapshot has nothing to restore."
|
|
41
|
+
: "Confirm restore? Y restore · N/Esc cancel"
|
|
42
|
+
};
|
|
43
|
+
case "preview-failed":
|
|
44
|
+
return {
|
|
45
|
+
...state,
|
|
46
|
+
phase: RECOVERY_PHASE.FAILED,
|
|
47
|
+
error: action.error ?? "preview-failed",
|
|
48
|
+
message: action.message ?? "Rollback preview failed.",
|
|
49
|
+
preview: state.preview
|
|
50
|
+
};
|
|
51
|
+
case "apply-start":
|
|
52
|
+
return { ...state, phase: RECOVERY_PHASE.APPLYING, message: "Restoring snapshot…" };
|
|
53
|
+
case "apply-done":
|
|
54
|
+
return {
|
|
55
|
+
phase: action.ok ? RECOVERY_PHASE.COMPLETED : RECOVERY_PHASE.FAILED,
|
|
56
|
+
preview: action.preview ?? state.preview,
|
|
57
|
+
receipt: action.receipt ?? null,
|
|
58
|
+
error: action.ok ? null : (action.reason ?? "apply-failed"),
|
|
59
|
+
selectedSnapshot: state.selectedSnapshot,
|
|
60
|
+
message: action.message ?? (action.ok ? "Rollback complete." : "Rollback failed.")
|
|
61
|
+
};
|
|
62
|
+
case "cancel":
|
|
63
|
+
return {
|
|
64
|
+
...createRecoveryActionState(),
|
|
65
|
+
message: "Cancelled — previous snapshot kept, no restore written."
|
|
66
|
+
};
|
|
67
|
+
default:
|
|
68
|
+
return state;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function listRecoverySnapshots(snapshot) {
|
|
73
|
+
return snapshot?.backups?.snapshots ?? [];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function formatRecoveryLines({ snapshot, recoveryAction, listIndex = 0 }) {
|
|
77
|
+
const backups = listRecoverySnapshots(snapshot);
|
|
78
|
+
const events = snapshot?.history?.events ?? [];
|
|
79
|
+
const phase = recoveryAction?.phase ?? RECOVERY_PHASE.IDLE;
|
|
80
|
+
const lines = [
|
|
81
|
+
`Activity & recovery · ${phase}`,
|
|
82
|
+
`History: ${events.length} recent event(s)`,
|
|
83
|
+
...events.slice(0, 3).map((event) => `${event.command ?? event.type ?? "event"} · ${event.action ?? ""} · ${event.timestamp ?? ""}`),
|
|
84
|
+
"",
|
|
85
|
+
`Snapshots: ${snapshot?.backups?.count ?? backups.length}`
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
if (backups.length === 0) {
|
|
89
|
+
lines.push("No global snapshots yet.");
|
|
90
|
+
} else {
|
|
91
|
+
backups.forEach((entry, index) => {
|
|
92
|
+
const mark = index === listIndex ? "›" : " ";
|
|
93
|
+
lines.push(`${mark} ${entry.name} · ${entry.fileCount ?? "?"} files`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (recoveryAction?.message) lines.push("", recoveryAction.message);
|
|
98
|
+
const preview = recoveryAction?.preview;
|
|
99
|
+
if (preview) {
|
|
100
|
+
lines.push(`Snapshot · ${preview.snapshot}`);
|
|
101
|
+
for (const file of preview.files ?? []) lines.push(` restore · ${file.displayPath}`);
|
|
102
|
+
if (preview.fingerprint) lines.push(`Fingerprint · ${preview.fingerprint.slice(0, 12)}…`);
|
|
103
|
+
}
|
|
104
|
+
const receipt = recoveryAction?.receipt;
|
|
105
|
+
if (receipt) {
|
|
106
|
+
lines.push("", `Receipt · ${receipt.action}`);
|
|
107
|
+
if (receipt.safetyBackup) lines.push(`Safety backup · ${receipt.safetyBackup}`);
|
|
108
|
+
for (const path of receipt.restored ?? []) lines.push(` restored · ${path}`);
|
|
109
|
+
}
|
|
110
|
+
if (phase === RECOVERY_PHASE.IDLE || phase === RECOVERY_PHASE.COMPLETED || phase === RECOVERY_PHASE.FAILED) {
|
|
111
|
+
lines.push("", "Enter preview · Y restore · N/Esc cancel · R re-scan");
|
|
112
|
+
}
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function buildRecoveryFooterParts(phase) {
|
|
117
|
+
if (phase === RECOVERY_PHASE.PREVIEWING || phase === RECOVERY_PHASE.APPLYING) return ["Working…", "Esc Back"];
|
|
118
|
+
if (phase === RECOVERY_PHASE.CONFIRMING) return ["Y Restore", "N/Esc Cancel"];
|
|
119
|
+
return ["↑↓ Select", "Enter Preview", "R Re-scan", "Esc Back"];
|
|
120
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ORCHESTRATOR_VIEWS } from "./orchestrator-state.js";
|
|
2
|
+
|
|
3
|
+
export const RUNS_HUB_ITEMS = [
|
|
4
|
+
{
|
|
5
|
+
id: "active",
|
|
6
|
+
label: "Active runs",
|
|
7
|
+
view: ORCHESTRATOR_VIEWS.ACTIVE_RUNS,
|
|
8
|
+
description: "Inspect and cancel supervised runs that are currently executing."
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "history",
|
|
12
|
+
label: "History",
|
|
13
|
+
view: ORCHESTRATOR_VIEWS.RECENT_RUNS,
|
|
14
|
+
description: "Review completed and failed run outcomes."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "launch",
|
|
18
|
+
label: "New run",
|
|
19
|
+
view: ORCHESTRATOR_VIEWS.LAUNCH,
|
|
20
|
+
action: "launch",
|
|
21
|
+
description: "Start a supervised run after governance is healthy."
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export function isRunsBranchView(view) {
|
|
26
|
+
return view === ORCHESTRATOR_VIEWS.RUNS
|
|
27
|
+
|| view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
|
|
28
|
+
|| view === ORCHESTRATOR_VIEWS.RECENT_RUNS
|
|
29
|
+
|| view === ORCHESTRATOR_VIEWS.LAUNCH
|
|
30
|
+
|| view === ORCHESTRATOR_VIEWS.RUN_DETAIL;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function isRunsChildView(view) {
|
|
34
|
+
return view === ORCHESTRATOR_VIEWS.ACTIVE_RUNS
|
|
35
|
+
|| view === ORCHESTRATOR_VIEWS.RECENT_RUNS
|
|
36
|
+
|| view === ORCHESTRATOR_VIEWS.LAUNCH;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveRunsHubItem(listIndex = 0, items = RUNS_HUB_ITEMS) {
|
|
40
|
+
if (items.length === 0) return null;
|
|
41
|
+
const index = Math.min(Math.max(0, listIndex), items.length - 1);
|
|
42
|
+
return items[index] ?? null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function formatRunsHubLines(items = RUNS_HUB_ITEMS) {
|
|
46
|
+
return items.map((item) => `${item.label} — ${item.description}`);
|
|
47
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export const CONTROL_PLANE_AUTO_SCAN = Object.freeze({
|
|
2
|
+
includeDiff: true,
|
|
3
|
+
includeExplain: false,
|
|
4
|
+
includeRuntime: false
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
export async function loadCockpitScanBundle({
|
|
8
|
+
homeDir,
|
|
9
|
+
workspaceRoot,
|
|
10
|
+
packageName,
|
|
11
|
+
packageRoot,
|
|
12
|
+
cliVersion,
|
|
13
|
+
buildDashboard,
|
|
14
|
+
buildDiagnostics,
|
|
15
|
+
buildSnapshot
|
|
16
|
+
}) {
|
|
17
|
+
const [dashboard, diagnostics, snapshot] = await Promise.all([
|
|
18
|
+
buildDashboard({ homeDir, workspaceRoot, cliVersion }),
|
|
19
|
+
buildDiagnostics({ homeDir, workspaceRoot, packageName, packageRoot, cliVersion }),
|
|
20
|
+
buildSnapshot({
|
|
21
|
+
homeDir,
|
|
22
|
+
workspaceRoot,
|
|
23
|
+
packageName,
|
|
24
|
+
packageRoot,
|
|
25
|
+
cliVersion,
|
|
26
|
+
...CONTROL_PLANE_AUTO_SCAN
|
|
27
|
+
})
|
|
28
|
+
]);
|
|
29
|
+
return { dashboard, diagnostics, snapshot };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Serialize overlapping reloads and drop stale completions.
|
|
34
|
+
* Callers keep prior error/loading until a non-stale success updates state.
|
|
35
|
+
*/
|
|
36
|
+
export function createSerializedReloader(runLoad) {
|
|
37
|
+
let generation = 0;
|
|
38
|
+
let tail = Promise.resolve();
|
|
39
|
+
|
|
40
|
+
return function reload() {
|
|
41
|
+
const gen = ++generation;
|
|
42
|
+
const job = async () => {
|
|
43
|
+
try {
|
|
44
|
+
const result = await runLoad();
|
|
45
|
+
if (gen !== generation) {
|
|
46
|
+
return { stale: true, result: null, error: null };
|
|
47
|
+
}
|
|
48
|
+
return { stale: false, result, error: null };
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (gen !== generation) {
|
|
51
|
+
return { stale: true, result: null, error: null };
|
|
52
|
+
}
|
|
53
|
+
return { stale: false, result: null, error };
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const next = tail.then(job, job);
|
|
57
|
+
tail = next.then(() => undefined, () => undefined);
|
|
58
|
+
return next;
|
|
59
|
+
};
|
|
60
|
+
}
|