dev-cockpit 0.3.2 → 0.3.4
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/dist/cockpit/panes/FilterModal.d.ts.map +1 -1
- package/dist/cockpit/panes/Health.d.ts.map +1 -1
- package/dist/cockpit/state/store.d.ts +13 -0
- package/dist/cockpit/state/store.d.ts.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/init-config-wizard.d.ts.map +1 -1
- package/dist/core/config.d.ts +24 -7
- package/dist/core/config.d.ts.map +1 -1
- package/dist/health/remediations.d.ts +15 -1
- package/dist/health/remediations.d.ts.map +1 -1
- package/dist/health/types.d.ts +9 -2
- package/dist/health/types.d.ts.map +1 -1
- package/dist/health/useHealth.d.ts +7 -0
- package/dist/health/useHealth.d.ts.map +1 -1
- package/dist/index.js +179 -57
- package/dist/index.js.map +3 -3
- package/examples/cockpit.schema.json +20 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15378,18 +15378,18 @@ var require_react_jsx_runtime_development = __commonJS({
|
|
|
15378
15378
|
function isValidElement(object) {
|
|
15379
15379
|
return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
|
|
15380
15380
|
}
|
|
15381
|
-
var
|
|
15381
|
+
var React8 = require_react(), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React8.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
|
|
15382
15382
|
return null;
|
|
15383
15383
|
};
|
|
15384
|
-
|
|
15384
|
+
React8 = {
|
|
15385
15385
|
react_stack_bottom_frame: function(callStackForError) {
|
|
15386
15386
|
return callStackForError();
|
|
15387
15387
|
}
|
|
15388
15388
|
};
|
|
15389
15389
|
var specialPropKeyWarningShown;
|
|
15390
15390
|
var didWarnAboutElementRef = {};
|
|
15391
|
-
var unknownOwnerDebugStack =
|
|
15392
|
-
|
|
15391
|
+
var unknownOwnerDebugStack = React8.react_stack_bottom_frame.bind(
|
|
15392
|
+
React8,
|
|
15393
15393
|
UnknownOwner
|
|
15394
15394
|
)();
|
|
15395
15395
|
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
|
|
@@ -83935,7 +83935,15 @@ var HighlightSchema = external_exports.object({
|
|
|
83935
83935
|
severity: external_exports.enum(["info", "warn", "error"]).optional().default("info")
|
|
83936
83936
|
});
|
|
83937
83937
|
var RemediationSchema = external_exports.object({
|
|
83938
|
-
|
|
83938
|
+
/**
|
|
83939
|
+
* Optional keypress binding on the Health pane. When omitted, the
|
|
83940
|
+
* remediation is documentation-only — the row shows the label but pressing
|
|
83941
|
+
* any key does nothing for this entry. Useful when several health entries
|
|
83942
|
+
* share the same shell command and you only want ONE row to be the
|
|
83943
|
+
* trigger — see `docker compose up -d` covering all four container-running
|
|
83944
|
+
* checks in the awc wrapper config.
|
|
83945
|
+
*/
|
|
83946
|
+
key: external_exports.string().optional(),
|
|
83939
83947
|
label: external_exports.string(),
|
|
83940
83948
|
command: external_exports.string(),
|
|
83941
83949
|
cwd: external_exports.string().optional()
|
|
@@ -83999,6 +84007,7 @@ var ComposerSettingsSchema = external_exports.object({
|
|
|
83999
84007
|
*/
|
|
84000
84008
|
packageDirs: external_exports.array(external_exports.string()).optional().default(["."])
|
|
84001
84009
|
});
|
|
84010
|
+
var KeybindingsSchema = external_exports.record(external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]));
|
|
84002
84011
|
var MountSettingsSchema = external_exports.object({
|
|
84003
84012
|
/**
|
|
84004
84013
|
* Override path for the generated docker-compose overlay. When unset
|
|
@@ -84032,6 +84041,7 @@ var BaseCockpitConfigSchema = external_exports.object({
|
|
|
84032
84041
|
manifestFile: "mount.manifest.json"
|
|
84033
84042
|
}),
|
|
84034
84043
|
composer: ComposerSettingsSchema.optional().default({ packageDirs: ["."] }),
|
|
84044
|
+
keybindings: KeybindingsSchema.optional().default({}),
|
|
84035
84045
|
/** Which pane the cockpit lands on when it boots. Profile may override. */
|
|
84036
84046
|
defaultPane: external_exports.enum(["repos", "output", "health", "help"]).optional().default("repos"),
|
|
84037
84047
|
/** Named keystroke-bound shell commands surfaced via the `:` palette. */
|
|
@@ -84043,6 +84053,16 @@ var BaseCockpitConfigSchema = external_exports.object({
|
|
|
84043
84053
|
*/
|
|
84044
84054
|
profile: external_exports.record(external_exports.unknown()).optional().default({})
|
|
84045
84055
|
});
|
|
84056
|
+
function normaliseKeybindings(raw) {
|
|
84057
|
+
const out = {};
|
|
84058
|
+
if (!raw) return out;
|
|
84059
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
84060
|
+
const ids = Array.isArray(value) ? value : [value];
|
|
84061
|
+
const clean = ids.filter((s) => typeof s === "string" && s.length > 0);
|
|
84062
|
+
if (clean.length > 0) out[key] = clean;
|
|
84063
|
+
}
|
|
84064
|
+
return out;
|
|
84065
|
+
}
|
|
84046
84066
|
var ConfigVersionError = class extends Error {
|
|
84047
84067
|
constructor(filePath, found, supported) {
|
|
84048
84068
|
super(
|
|
@@ -84158,7 +84178,7 @@ var {
|
|
|
84158
84178
|
} = import_index.default;
|
|
84159
84179
|
|
|
84160
84180
|
// src/cockpit/Cockpit.tsx
|
|
84161
|
-
var
|
|
84181
|
+
var import_react9 = __toESM(require_react(), 1);
|
|
84162
84182
|
|
|
84163
84183
|
// src/cockpit/hooks/useCockpitStore.ts
|
|
84164
84184
|
var import_react = __toESM(require_react(), 1);
|
|
@@ -84204,6 +84224,8 @@ var cockpitStore = createStore()((set, get2) => ({
|
|
|
84204
84224
|
selectedRepoIndex: 0,
|
|
84205
84225
|
output: [],
|
|
84206
84226
|
outputFilter: {},
|
|
84227
|
+
knownSources: [],
|
|
84228
|
+
keybindings: {},
|
|
84207
84229
|
activeModal: null,
|
|
84208
84230
|
actions: [],
|
|
84209
84231
|
commandFilter: "",
|
|
@@ -84257,7 +84279,8 @@ var cockpitStore = createStore()((set, get2) => ({
|
|
|
84257
84279
|
appendOutput: (line2) => set((state) => {
|
|
84258
84280
|
const next = [...state.output, line2];
|
|
84259
84281
|
const capped = next.length > MAX_OUTPUT_LINES ? next.slice(next.length - MAX_OUTPUT_LINES) : next;
|
|
84260
|
-
|
|
84282
|
+
const knownSources = state.knownSources.includes(line2.source) ? state.knownSources : [...state.knownSources, line2.source];
|
|
84283
|
+
return { output: capped, knownSources };
|
|
84261
84284
|
}),
|
|
84262
84285
|
clearOutput: () => set({ output: [] }),
|
|
84263
84286
|
setFilter: (filter) => set({ outputFilter: filter }),
|
|
@@ -84296,6 +84319,7 @@ var cockpitStore = createStore()((set, get2) => ({
|
|
|
84296
84319
|
setActiveRemediation: (remediation) => set({ activeRemediation: remediation }),
|
|
84297
84320
|
setHelpConfig: (config) => set({ helpConfig: config }),
|
|
84298
84321
|
setFocus: (focus) => set({ focus }),
|
|
84322
|
+
setKeybindings: (bindings) => set({ keybindings: bindings }),
|
|
84299
84323
|
setActions: (actions) => set({ actions }),
|
|
84300
84324
|
setCommandFilter: (filter) => set((state) => {
|
|
84301
84325
|
const filtered = filterActions(state.actions, filter);
|
|
@@ -84668,7 +84692,17 @@ function RecentErrorRow({ err }) {
|
|
|
84668
84692
|
}
|
|
84669
84693
|
|
|
84670
84694
|
// src/cockpit/panes/Health.tsx
|
|
84695
|
+
var import_react4 = __toESM(require_react(), 1);
|
|
84671
84696
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
84697
|
+
function buildReverseKeybindings(bindings) {
|
|
84698
|
+
const out = {};
|
|
84699
|
+
for (const [key, ids] of Object.entries(bindings)) {
|
|
84700
|
+
for (const id of ids) {
|
|
84701
|
+
if (!(id in out)) out[id] = key;
|
|
84702
|
+
}
|
|
84703
|
+
}
|
|
84704
|
+
return out;
|
|
84705
|
+
}
|
|
84672
84706
|
var SEVERITY_GLYPH = { ok: "\u2713", warn: "\u26A0", error: "\u2717" };
|
|
84673
84707
|
var SEVERITY_COLOR = {
|
|
84674
84708
|
ok: "green",
|
|
@@ -84682,6 +84716,8 @@ function Health() {
|
|
|
84682
84716
|
const focus = useCockpitStore((s) => s.focus);
|
|
84683
84717
|
const notificationsEnabledSession = useCockpitStore((s) => s.notificationsEnabledSession);
|
|
84684
84718
|
const activeRemediation = useCockpitStore((s) => s.activeRemediation);
|
|
84719
|
+
const keybindings = useCockpitStore((s) => s.keybindings);
|
|
84720
|
+
const idToKey = (0, import_react4.useMemo)(() => buildReverseKeybindings(keybindings), [keybindings]);
|
|
84685
84721
|
const isFocused = focus === "health";
|
|
84686
84722
|
if (health.length === 0) {
|
|
84687
84723
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexDirection: "column", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: "running health checks\u2026" }) });
|
|
@@ -84698,7 +84734,8 @@ function Health() {
|
|
|
84698
84734
|
const isRunning = activeRemediation?.healthId === item.id;
|
|
84699
84735
|
const glyph = isRunning ? "\u2026" : SEVERITY_GLYPH[item.severity] ?? "?";
|
|
84700
84736
|
const color = isRunning ? "yellow" : SEVERITY_COLOR[item.severity] ?? "white";
|
|
84701
|
-
const
|
|
84737
|
+
const displayKey = idToKey[item.id] ?? item.remediationKey ?? null;
|
|
84738
|
+
const remKey = displayKey ? ` [${displayKey}]` : "";
|
|
84702
84739
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
84703
84740
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { children: [
|
|
84704
84741
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: isSelected ? "cyan" : void 0, children: isSelected ? "\u25B6 " : " " }),
|
|
@@ -84721,7 +84758,7 @@ function Health() {
|
|
|
84721
84758
|
}
|
|
84722
84759
|
|
|
84723
84760
|
// src/cockpit/panes/Help.tsx
|
|
84724
|
-
var
|
|
84761
|
+
var import_react5 = __toESM(require_react(), 1);
|
|
84725
84762
|
|
|
84726
84763
|
// src/cockpit/help/loader.ts
|
|
84727
84764
|
import fs5 from "node:fs";
|
|
@@ -87532,7 +87569,7 @@ function Help2() {
|
|
|
87532
87569
|
const helpConfig = useCockpitStore((s) => s.helpConfig);
|
|
87533
87570
|
const { stdout } = use_stdout_default();
|
|
87534
87571
|
const isActive = focus === "help";
|
|
87535
|
-
const initial = (0,
|
|
87572
|
+
const initial = (0, import_react5.useMemo)(() => {
|
|
87536
87573
|
const result = loadHelpPages({
|
|
87537
87574
|
sources: helpConfig.sources,
|
|
87538
87575
|
defaultPage: helpConfig.defaultPage
|
|
@@ -87541,17 +87578,17 @@ function Help2() {
|
|
|
87541
87578
|
return { pages: [FALLBACK_PAGE], defaultIndex: 0 };
|
|
87542
87579
|
}, [helpConfig.sources, helpConfig.defaultPage]);
|
|
87543
87580
|
const pages = initial.pages;
|
|
87544
|
-
const [pageIndex, setPageIndex] = (0,
|
|
87545
|
-
const [scrollOffset, setScrollOffset] = (0,
|
|
87546
|
-
const lastPageIndexRef = (0,
|
|
87547
|
-
(0,
|
|
87581
|
+
const [pageIndex, setPageIndex] = (0, import_react5.useState)(initial.defaultIndex);
|
|
87582
|
+
const [scrollOffset, setScrollOffset] = (0, import_react5.useState)(0);
|
|
87583
|
+
const lastPageIndexRef = (0, import_react5.useRef)(pageIndex);
|
|
87584
|
+
(0, import_react5.useEffect)(() => {
|
|
87548
87585
|
if (lastPageIndexRef.current !== pageIndex) {
|
|
87549
87586
|
lastPageIndexRef.current = pageIndex;
|
|
87550
87587
|
setScrollOffset(0);
|
|
87551
87588
|
}
|
|
87552
87589
|
}, [pageIndex]);
|
|
87553
87590
|
const activePage = pages[pageIndex] ?? pages[0];
|
|
87554
|
-
const renderedLines = (0,
|
|
87591
|
+
const renderedLines = (0, import_react5.useMemo)(
|
|
87555
87592
|
() => renderMarkdown(activePage.body).split("\n"),
|
|
87556
87593
|
[activePage.body]
|
|
87557
87594
|
);
|
|
@@ -87679,22 +87716,70 @@ function Footer({ legends } = {}) {
|
|
|
87679
87716
|
}
|
|
87680
87717
|
|
|
87681
87718
|
// src/cockpit/panes/FilterModal.tsx
|
|
87682
|
-
var
|
|
87719
|
+
var import_react6 = __toESM(require_react(), 1);
|
|
87683
87720
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
87721
|
+
var SEVERITIES = [void 0, "info", "warn", "error"];
|
|
87684
87722
|
function FilterModal() {
|
|
87685
87723
|
const outputFilter = useCockpitStore((s) => s.outputFilter);
|
|
87686
|
-
const
|
|
87724
|
+
const knownSources = useCockpitStore((s) => s.knownSources);
|
|
87725
|
+
const [severityDraft, setSeverityDraft] = (0, import_react6.useState)(
|
|
87687
87726
|
outputFilter.severity
|
|
87688
87727
|
);
|
|
87689
|
-
const
|
|
87728
|
+
const initialSelected = new Set(
|
|
87729
|
+
outputFilter.sources && outputFilter.sources.length > 0 ? outputFilter.sources : knownSources
|
|
87730
|
+
);
|
|
87731
|
+
const [selectedSources, setSelectedSources] = (0, import_react6.useState)(initialSelected);
|
|
87732
|
+
const [cursor, setCursor] = (0, import_react6.useState)(0);
|
|
87733
|
+
const sources = knownSources;
|
|
87734
|
+
const hasSources = sources.length > 0;
|
|
87690
87735
|
use_input_default((input, key) => {
|
|
87691
87736
|
if (input === "s") {
|
|
87692
87737
|
const idx = SEVERITIES.indexOf(severityDraft);
|
|
87693
|
-
|
|
87694
|
-
|
|
87738
|
+
setSeverityDraft(SEVERITIES[(idx + 1) % SEVERITIES.length]);
|
|
87739
|
+
return;
|
|
87740
|
+
}
|
|
87741
|
+
if (hasSources) {
|
|
87742
|
+
if (key.upArrow) {
|
|
87743
|
+
setCursor((c3) => Math.max(0, c3 - 1));
|
|
87744
|
+
return;
|
|
87745
|
+
}
|
|
87746
|
+
if (key.downArrow) {
|
|
87747
|
+
setCursor((c3) => Math.min(sources.length - 1, c3 + 1));
|
|
87748
|
+
return;
|
|
87749
|
+
}
|
|
87750
|
+
if (input === " ") {
|
|
87751
|
+
const src = sources[cursor];
|
|
87752
|
+
if (src) {
|
|
87753
|
+
setSelectedSources((prev) => {
|
|
87754
|
+
const next = new Set(prev);
|
|
87755
|
+
if (next.has(src)) next.delete(src);
|
|
87756
|
+
else next.add(src);
|
|
87757
|
+
return next;
|
|
87758
|
+
});
|
|
87759
|
+
}
|
|
87760
|
+
return;
|
|
87761
|
+
}
|
|
87762
|
+
if (input === "a") {
|
|
87763
|
+
setSelectedSources(new Set(sources));
|
|
87764
|
+
return;
|
|
87765
|
+
}
|
|
87766
|
+
if (input === "n") {
|
|
87767
|
+
setSelectedSources(/* @__PURE__ */ new Set());
|
|
87768
|
+
return;
|
|
87769
|
+
}
|
|
87770
|
+
}
|
|
87771
|
+
if (key.escape) {
|
|
87772
|
+
cockpitStore.getState().setActiveModal(null);
|
|
87773
|
+
return;
|
|
87695
87774
|
}
|
|
87696
|
-
if (key.return
|
|
87697
|
-
|
|
87775
|
+
if (key.return) {
|
|
87776
|
+
const allSelected = selectedSources.size === sources.length;
|
|
87777
|
+
const next = {
|
|
87778
|
+
...outputFilter,
|
|
87779
|
+
severity: severityDraft,
|
|
87780
|
+
sources: allSelected ? void 0 : Array.from(selectedSources)
|
|
87781
|
+
};
|
|
87782
|
+
cockpitStore.getState().setFilter(next);
|
|
87698
87783
|
cockpitStore.getState().setActiveModal(null);
|
|
87699
87784
|
}
|
|
87700
87785
|
});
|
|
@@ -87702,20 +87787,38 @@ function FilterModal() {
|
|
|
87702
87787
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: " Filter Output " }),
|
|
87703
87788
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87704
87789
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
|
|
87705
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: "Severity (s
|
|
87790
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: "Severity (s): " }),
|
|
87706
87791
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "cyan", children: severityDraft ?? "all" })
|
|
87707
87792
|
] }),
|
|
87708
87793
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87794
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: "Sources" }),
|
|
87795
|
+
hasSources ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
87796
|
+
sources.map((src, idx) => {
|
|
87797
|
+
const checked = selectedSources.has(src);
|
|
87798
|
+
const isCursor = idx === cursor;
|
|
87799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
|
|
87800
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u25B6 " : " " }),
|
|
87801
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
|
|
87802
|
+
"[",
|
|
87803
|
+
checked ? "x" : " ",
|
|
87804
|
+
"] "
|
|
87805
|
+
] }),
|
|
87806
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: isCursor ? "cyan" : void 0, children: src })
|
|
87807
|
+
] }, src);
|
|
87808
|
+
}),
|
|
87809
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " \u2191\u2193 move \xB7 space toggle \xB7 a all \xB7 n none" })
|
|
87810
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: " (none yet \u2014 output sources appear as they emit)" }),
|
|
87811
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87709
87812
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: "Enter = apply \xB7 Esc = cancel" })
|
|
87710
87813
|
] }) });
|
|
87711
87814
|
}
|
|
87712
87815
|
|
|
87713
87816
|
// src/cockpit/panes/SearchModal.tsx
|
|
87714
|
-
var
|
|
87817
|
+
var import_react7 = __toESM(require_react(), 1);
|
|
87715
87818
|
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
87716
87819
|
function SearchModal() {
|
|
87717
87820
|
const outputFilter = useCockpitStore((s) => s.outputFilter);
|
|
87718
|
-
const [query, setQuery] = (0,
|
|
87821
|
+
const [query, setQuery] = (0, import_react7.useState)(outputFilter.search ?? "");
|
|
87719
87822
|
use_input_default((input, key) => {
|
|
87720
87823
|
if (key.escape) {
|
|
87721
87824
|
cockpitStore.getState().setActiveModal(null);
|
|
@@ -87950,7 +88053,7 @@ function useGlobalKeys(opts) {
|
|
|
87950
88053
|
}
|
|
87951
88054
|
|
|
87952
88055
|
// src/health/useHealth.ts
|
|
87953
|
-
var
|
|
88056
|
+
var import_react8 = __toESM(require_react(), 1);
|
|
87954
88057
|
|
|
87955
88058
|
// src/health/scheduler.ts
|
|
87956
88059
|
import path9 from "node:path";
|
|
@@ -87974,7 +88077,7 @@ async function runChecks(checks, triggerSet, ctx) {
|
|
|
87974
88077
|
label: check.label,
|
|
87975
88078
|
severity: "warn",
|
|
87976
88079
|
detail: `check failed with error: ${String(err)}`,
|
|
87977
|
-
remediationKey: check.remediation.key
|
|
88080
|
+
remediationKey: check.remediation.key ?? null
|
|
87978
88081
|
};
|
|
87979
88082
|
}
|
|
87980
88083
|
})
|
|
@@ -88044,7 +88147,7 @@ var HealthScheduler = class {
|
|
|
88044
88147
|
label: check.label,
|
|
88045
88148
|
severity: "warn",
|
|
88046
88149
|
detail: `check failed with error: ${String(err)}`,
|
|
88047
|
-
remediationKey: check.remediation.key
|
|
88150
|
+
remediationKey: check.remediation.key ?? null
|
|
88048
88151
|
};
|
|
88049
88152
|
}
|
|
88050
88153
|
})
|
|
@@ -88083,10 +88186,21 @@ var HealthScheduler = class {
|
|
|
88083
88186
|
};
|
|
88084
88187
|
|
|
88085
88188
|
// src/health/remediations.ts
|
|
88086
|
-
|
|
88087
|
-
const
|
|
88088
|
-
if (
|
|
88089
|
-
|
|
88189
|
+
function findChecksByKey(key, checks, keybindings) {
|
|
88190
|
+
const ids = keybindings?.[key];
|
|
88191
|
+
if (ids && ids.length > 0) {
|
|
88192
|
+
return ids.map((id) => checks.find((c4) => c4.id === id)).filter((c4) => Boolean(c4));
|
|
88193
|
+
}
|
|
88194
|
+
const c3 = checks.find((c4) => c4.remediation.key === key);
|
|
88195
|
+
return c3 ? [c3] : [];
|
|
88196
|
+
}
|
|
88197
|
+
async function runRemediation(key, checks, ctx, workspaceRoot, keybindings) {
|
|
88198
|
+
const matched = findChecksByKey(key, checks, keybindings);
|
|
88199
|
+
await Promise.all(
|
|
88200
|
+
matched.map(
|
|
88201
|
+
(check) => dispatchRemediation(check.remediation, ctx, workspaceRoot, check.id)
|
|
88202
|
+
)
|
|
88203
|
+
);
|
|
88090
88204
|
}
|
|
88091
88205
|
function findRemediation(key, checks) {
|
|
88092
88206
|
return checks.find((c3) => c3.remediation.key === key);
|
|
@@ -88158,7 +88272,7 @@ var containerRunning = (entry) => {
|
|
|
88158
88272
|
label: entry.label,
|
|
88159
88273
|
severity: running ? "ok" : entry.severity ?? "error",
|
|
88160
88274
|
detail: running ? `container matching '${container}' is running` : states.length > 0 ? `container matching '${container}' exists but is in state: ${states.join(", ")}` : `no container matching '${container}' is running`,
|
|
88161
|
-
remediationKey: entry.remediation.key
|
|
88275
|
+
remediationKey: entry.remediation.key ?? null
|
|
88162
88276
|
};
|
|
88163
88277
|
};
|
|
88164
88278
|
};
|
|
@@ -88186,7 +88300,7 @@ var portOpen = (entry) => {
|
|
|
88186
88300
|
label: entry.label,
|
|
88187
88301
|
severity: open2 ? "ok" : entry.severity ?? "error",
|
|
88188
88302
|
detail: open2 ? `${host}:${port} is reachable` : `${host}:${port} is not reachable`,
|
|
88189
|
-
remediationKey: entry.remediation.key
|
|
88303
|
+
remediationKey: entry.remediation.key ?? null
|
|
88190
88304
|
};
|
|
88191
88305
|
};
|
|
88192
88306
|
};
|
|
@@ -88214,7 +88328,7 @@ var httpOk = (entry) => {
|
|
|
88214
88328
|
label: entry.label,
|
|
88215
88329
|
severity: ok ? "ok" : entry.severity ?? "error",
|
|
88216
88330
|
detail: ok ? `${url} returned ${status4}` : detail || `${url} returned ${status4} (expected ${expect})`,
|
|
88217
|
-
remediationKey: entry.remediation.key
|
|
88331
|
+
remediationKey: entry.remediation.key ?? null
|
|
88218
88332
|
};
|
|
88219
88333
|
};
|
|
88220
88334
|
};
|
|
@@ -88231,7 +88345,7 @@ var fileExists = (entry) => {
|
|
|
88231
88345
|
label: entry.label,
|
|
88232
88346
|
severity: exists ? "ok" : entry.severity ?? "error",
|
|
88233
88347
|
detail: exists ? `${resolved} exists` : `${resolved} is missing`,
|
|
88234
|
-
remediationKey: entry.remediation.key
|
|
88348
|
+
remediationKey: entry.remediation.key ?? null
|
|
88235
88349
|
};
|
|
88236
88350
|
};
|
|
88237
88351
|
};
|
|
@@ -88250,7 +88364,7 @@ var execZero = (entry) => {
|
|
|
88250
88364
|
label: entry.label,
|
|
88251
88365
|
severity: ok ? "ok" : entry.severity ?? "error",
|
|
88252
88366
|
detail: ok ? `${command} ${args.join(" ")} exited 0` : `${command} ${args.join(" ")} exited ${exitCode}`,
|
|
88253
|
-
remediationKey: entry.remediation.key
|
|
88367
|
+
remediationKey: entry.remediation.key ?? null
|
|
88254
88368
|
};
|
|
88255
88369
|
};
|
|
88256
88370
|
};
|
|
@@ -88373,23 +88487,23 @@ function buildHealthContext(workspaceRoot, appendOutput) {
|
|
|
88373
88487
|
|
|
88374
88488
|
// src/health/useHealth.ts
|
|
88375
88489
|
function useHealth(opts) {
|
|
88376
|
-
const checks = (0,
|
|
88490
|
+
const checks = (0, import_react8.useMemo)(() => {
|
|
88377
88491
|
if (!opts) return [];
|
|
88378
88492
|
return buildHealthRegistry({
|
|
88379
88493
|
profileChecks: opts.profileChecks,
|
|
88380
88494
|
configEntries: opts.configEntries
|
|
88381
88495
|
});
|
|
88382
88496
|
}, [opts]);
|
|
88383
|
-
const checksRef = (0,
|
|
88384
|
-
const ctxRef = (0,
|
|
88385
|
-
const optsRef = (0,
|
|
88386
|
-
const schedulerRef = (0,
|
|
88387
|
-
(0,
|
|
88497
|
+
const checksRef = (0, import_react8.useRef)(checks);
|
|
88498
|
+
const ctxRef = (0, import_react8.useRef)(opts?.ctx);
|
|
88499
|
+
const optsRef = (0, import_react8.useRef)(opts);
|
|
88500
|
+
const schedulerRef = (0, import_react8.useRef)(null);
|
|
88501
|
+
(0, import_react8.useEffect)(() => {
|
|
88388
88502
|
checksRef.current = checks;
|
|
88389
88503
|
ctxRef.current = opts?.ctx;
|
|
88390
88504
|
optsRef.current = opts;
|
|
88391
88505
|
}, [checks, opts]);
|
|
88392
|
-
(0,
|
|
88506
|
+
(0, import_react8.useEffect)(() => {
|
|
88393
88507
|
if (!opts) return;
|
|
88394
88508
|
if (checks.length === 0) return;
|
|
88395
88509
|
const scheduler3 = new HealthScheduler({
|
|
@@ -88428,21 +88542,25 @@ function useHealth(opts) {
|
|
|
88428
88542
|
runRemediation: (key) => {
|
|
88429
88543
|
const list3 = checksRef.current;
|
|
88430
88544
|
const ctx = ctxRef.current ?? buildDefaultCtx(optsRef.current?.workspaceRoot ?? ".");
|
|
88431
|
-
const
|
|
88432
|
-
|
|
88545
|
+
const keybindings = optsRef.current?.keybindings;
|
|
88546
|
+
const matched = findChecksByKey(key, list3, keybindings);
|
|
88547
|
+
if (matched.length === 0) return null;
|
|
88548
|
+
const first = matched[0];
|
|
88549
|
+
const banner = matched.length === 1 ? first.remediation.label : `${matched.length} remediations`;
|
|
88433
88550
|
const promise = runRemediation(
|
|
88434
88551
|
key,
|
|
88435
88552
|
list3,
|
|
88436
88553
|
ctx,
|
|
88437
|
-
optsRef.current?.workspaceRoot ?? "."
|
|
88554
|
+
optsRef.current?.workspaceRoot ?? ".",
|
|
88555
|
+
keybindings
|
|
88438
88556
|
).finally(() => {
|
|
88439
88557
|
void schedulerRef.current?.runAll();
|
|
88440
88558
|
});
|
|
88441
88559
|
return {
|
|
88442
|
-
label:
|
|
88560
|
+
label: banner,
|
|
88443
88561
|
promise,
|
|
88444
|
-
healthId:
|
|
88445
|
-
healthLabel:
|
|
88562
|
+
healthId: first.id,
|
|
88563
|
+
healthLabel: first.label
|
|
88446
88564
|
};
|
|
88447
88565
|
}
|
|
88448
88566
|
};
|
|
@@ -88475,8 +88593,8 @@ function Cockpit(props) {
|
|
|
88475
88593
|
const { stdout } = use_stdout_default();
|
|
88476
88594
|
const focus = useCockpitStore((s) => s.focus);
|
|
88477
88595
|
const activeModal = useCockpitStore((s) => s.activeModal);
|
|
88478
|
-
const [rows, setRows] = (0,
|
|
88479
|
-
(0,
|
|
88596
|
+
const [rows, setRows] = (0, import_react9.useState)(stdout.rows ?? 24);
|
|
88597
|
+
(0, import_react9.useEffect)(() => {
|
|
88480
88598
|
const onResize = () => setRows(stdout.rows ?? 24);
|
|
88481
88599
|
stdout.on("resize", onResize);
|
|
88482
88600
|
return () => {
|
|
@@ -91219,7 +91337,7 @@ function createMountBrokenSymlinkCheck(opts) {
|
|
|
91219
91337
|
const severity = opts.severity ?? "error";
|
|
91220
91338
|
const triggers = opts.triggers ?? ["startup", "fsevent"];
|
|
91221
91339
|
const remediation = opts.remediation ?? DEFAULT_REMEDIATION;
|
|
91222
|
-
const remediationKey = remediation.key;
|
|
91340
|
+
const remediationKey = remediation.key ?? null;
|
|
91223
91341
|
const predicate = async (ctx) => {
|
|
91224
91342
|
const { workspaceRoot } = ctx;
|
|
91225
91343
|
let manifestPath2;
|
|
@@ -91310,7 +91428,7 @@ function hasLockfile(workspaceRoot) {
|
|
|
91310
91428
|
}
|
|
91311
91429
|
|
|
91312
91430
|
// src/runCockpit.ts
|
|
91313
|
-
var
|
|
91431
|
+
var import_react10 = __toESM(require_react(), 1);
|
|
91314
91432
|
var ENTER_ALT_SCREEN = "\x1B[?1049h\x1B[H";
|
|
91315
91433
|
var EXIT_ALT_SCREEN = "\x1B[?1049l";
|
|
91316
91434
|
function runCockpit(opts = {}) {
|
|
@@ -91349,7 +91467,7 @@ function runCockpit(opts = {}) {
|
|
|
91349
91467
|
throw err;
|
|
91350
91468
|
});
|
|
91351
91469
|
}
|
|
91352
|
-
const ink = render_default(
|
|
91470
|
+
const ink = render_default(import_react10.default.createElement(Cockpit, cockpitProps), { exitOnCtrlC: true });
|
|
91353
91471
|
return {
|
|
91354
91472
|
waitUntilExit: async () => {
|
|
91355
91473
|
try {
|
|
@@ -91457,6 +91575,7 @@ async function devCommand(opts = {}) {
|
|
|
91457
91575
|
const requestedHidden = requestedPane === "repos" && reposEmpty || requestedPane === "health" && healthEmpty;
|
|
91458
91576
|
const initialFocus = requestedHidden ? "output" : requestedPane;
|
|
91459
91577
|
cockpitStore.getState().setFocus(initialFocus);
|
|
91578
|
+
cockpitStore.getState().setKeybindings(normaliseKeybindings(config.keybindings));
|
|
91460
91579
|
const builtinActions = buildBuiltinActions(config);
|
|
91461
91580
|
const actions = buildActionRegistry(
|
|
91462
91581
|
[...config.actions],
|
|
@@ -91588,7 +91707,8 @@ async function devCommand(opts = {}) {
|
|
|
91588
91707
|
exclude: config.notifications.exclude
|
|
91589
91708
|
},
|
|
91590
91709
|
appName: config.appName,
|
|
91591
|
-
subscribeFsEvents: bootResult.subscribeFsEvents
|
|
91710
|
+
subscribeFsEvents: bootResult.subscribeFsEvents,
|
|
91711
|
+
keybindings: normaliseKeybindings(config.keybindings)
|
|
91592
91712
|
}
|
|
91593
91713
|
});
|
|
91594
91714
|
for (const proc of config.processes) {
|
|
@@ -91753,7 +91873,9 @@ function renderHealth(checks) {
|
|
|
91753
91873
|
break;
|
|
91754
91874
|
}
|
|
91755
91875
|
out.push(indent(` remediation:`, 1));
|
|
91756
|
-
|
|
91876
|
+
if (c3.remediation.key) {
|
|
91877
|
+
out.push(indent(` key: ${quote(c3.remediation.key)}`, 1));
|
|
91878
|
+
}
|
|
91757
91879
|
out.push(indent(` label: ${quote(c3.remediation.label)}`, 1));
|
|
91758
91880
|
out.push(indent(` command: ${quote(c3.remediation.command)}`, 1));
|
|
91759
91881
|
}
|