dev-cockpit 0.2.7 → 0.2.9
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 +32 -32
- package/bin/dev-cockpit.mjs +1 -1
- package/dist/buildCli.d.ts.map +1 -1
- package/dist/{chunk-A446TCT5.js → chunk-YTMK7EXK.js} +1 -1
- package/dist/chunk-YTMK7EXK.js.map +7 -0
- package/dist/cockpit/Footer.d.ts.map +1 -1
- package/dist/cockpit/hooks/useGlobalKeys.d.ts.map +1 -1
- package/dist/cockpit/panes/FilterModal.d.ts.map +1 -1
- package/dist/cockpit/panes/Output.d.ts.map +1 -1
- package/dist/cockpit/panes/Repos.d.ts.map +1 -1
- package/dist/cockpit/panes/SearchModal.d.ts.map +1 -1
- package/dist/cockpit/state/store.d.ts.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/init-config-wizard.d.ts.map +1 -1
- package/dist/commands/init-config.d.ts.map +1 -1
- package/dist/commands/link.d.ts.map +1 -1
- package/dist/commands/migrate-config.d.ts.map +1 -1
- package/dist/commands/mount.d.ts +16 -3
- package/dist/commands/mount.d.ts.map +1 -1
- package/dist/core/config-discovery.d.ts.map +1 -1
- package/dist/core/config.d.ts +13 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/manifest.d.ts.map +1 -1
- package/dist/core/migrations.d.ts.map +1 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/subprocess.d.ts.map +1 -1
- package/dist/core/types.d.ts +8 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/docker/highlights.d.ts.map +1 -1
- package/dist/health/builtin.d.ts.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +364 -159
- package/dist/index.js.map +3 -3
- package/dist/ink.d.ts +1 -1
- package/dist/ink.d.ts.map +1 -1
- package/dist/{link-VWT2VQH6.js → link-Y7OFHOUP.js} +4 -6
- package/dist/link-Y7OFHOUP.js.map +7 -0
- package/dist/mount/compose.d.ts.map +1 -1
- package/dist/mount/symlinks.d.ts.map +1 -1
- package/dist/mount/types.d.ts +6 -0
- package/dist/mount/types.d.ts.map +1 -1
- package/docs/commands.md +8 -8
- package/docs/config-reference.md +45 -41
- package/docs/health.md +32 -22
- package/docs/init-config.md +16 -16
- package/docs/mount.md +8 -7
- package/docs/notifications.md +3 -3
- package/docs/panes.md +5 -5
- package/docs/processes.md +7 -5
- package/examples/cockpit.schema.json +222 -57
- package/examples/cockpit.yaml +8 -10
- package/package.json +99 -93
- package/prettier-config.json +7 -0
- package/dist/chunk-A446TCT5.js.map +0 -7
- package/dist/link-VWT2VQH6.js.map +0 -7
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
readManifest,
|
|
24
24
|
removeMapping,
|
|
25
25
|
setMapping
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-YTMK7EXK.js";
|
|
27
27
|
import {
|
|
28
28
|
__commonJS,
|
|
29
29
|
__export,
|
|
@@ -83972,6 +83972,7 @@ var MountSchema = external_exports.object({
|
|
|
83972
83972
|
hostPath: external_exports.string(),
|
|
83973
83973
|
containerPath: external_exports.string().optional(),
|
|
83974
83974
|
kind: external_exports.enum(["bind", "symlink-only"]).optional(),
|
|
83975
|
+
alternativeSources: external_exports.array(external_exports.string()).optional(),
|
|
83975
83976
|
meta: external_exports.record(external_exports.unknown()).optional()
|
|
83976
83977
|
}).refine(
|
|
83977
83978
|
(m) => m.kind === "symlink-only" ? true : typeof m.containerPath === "string" && m.containerPath.length > 0,
|
|
@@ -83998,7 +83999,9 @@ var MountSettingsSchema = external_exports.object({
|
|
|
83998
83999
|
*/
|
|
83999
84000
|
overlayPath: external_exports.string().optional(),
|
|
84000
84001
|
/** Basename inside stateDir for the manifest. */
|
|
84001
|
-
manifestFile: external_exports.string().optional().default("mount.manifest.json")
|
|
84002
|
+
manifestFile: external_exports.string().optional().default("mount.manifest.json"),
|
|
84003
|
+
/** Target compose service. Unset = first in docker.services. */
|
|
84004
|
+
service: external_exports.string().optional()
|
|
84002
84005
|
});
|
|
84003
84006
|
var BaseCockpitConfigSchema = external_exports.object({
|
|
84004
84007
|
version: external_exports.number().int(),
|
|
@@ -84180,9 +84183,7 @@ var FOCUS_ORDER = ["repos", "output", "health", "help"];
|
|
|
84180
84183
|
function filterActions(actions, filter) {
|
|
84181
84184
|
if (!filter) return actions;
|
|
84182
84185
|
const f = filter.toLowerCase();
|
|
84183
|
-
return actions.filter(
|
|
84184
|
-
(a2) => a2.id.toLowerCase().includes(f) || a2.label.toLowerCase().includes(f)
|
|
84185
|
-
);
|
|
84186
|
+
return actions.filter((a2) => a2.id.toLowerCase().includes(f) || a2.label.toLowerCase().includes(f));
|
|
84186
84187
|
}
|
|
84187
84188
|
var cockpitStore = createStore()((set, get2) => ({
|
|
84188
84189
|
repos: {},
|
|
@@ -84451,7 +84452,7 @@ function Repos() {
|
|
|
84451
84452
|
const heading2 = kind === "repo" ? "Repos" : kind === "docker" ? "Docker" : "Processes";
|
|
84452
84453
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
84453
84454
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { dimColor: true, children: [
|
|
84454
|
-
"
|
|
84455
|
+
" ",
|
|
84455
84456
|
heading2
|
|
84456
84457
|
] }),
|
|
84457
84458
|
entriesInKind.map(({ key, idx, entry }) => {
|
|
@@ -84488,7 +84489,7 @@ function Repos() {
|
|
|
84488
84489
|
" ",
|
|
84489
84490
|
a2.label
|
|
84490
84491
|
] }),
|
|
84491
|
-
isDefault && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: "
|
|
84492
|
+
isDefault && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { dimColor: true, children: " (default)" })
|
|
84492
84493
|
] }, a2.id);
|
|
84493
84494
|
})
|
|
84494
84495
|
]
|
|
@@ -84589,9 +84590,7 @@ function Output() {
|
|
|
84589
84590
|
} else if (key.downArrow) {
|
|
84590
84591
|
setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
84591
84592
|
} else if (key.pageUp) {
|
|
84592
|
-
setScrollOffset(
|
|
84593
|
-
(prev) => Math.min(prev + visibleLines, Math.max(0, total - visibleLines))
|
|
84594
|
-
);
|
|
84593
|
+
setScrollOffset((prev) => Math.min(prev + visibleLines, Math.max(0, total - visibleLines)));
|
|
84595
84594
|
} else if (key.pageDown) {
|
|
84596
84595
|
setScrollOffset((prev) => Math.max(0, prev - visibleLines));
|
|
84597
84596
|
} else if (key.return) {
|
|
@@ -87651,7 +87650,9 @@ function Footer({ legends } = {}) {
|
|
|
87651
87650
|
if (!key) return NAV_HINT;
|
|
87652
87651
|
const keyed = actionsForRepoRow(s.actions, key).filter((a2) => a2.key);
|
|
87653
87652
|
if (keyed.length === 0) return NAV_HINT;
|
|
87654
|
-
return [NAV_HINT, ...keyed.map((a2) => `[${a2.key}] ${shortLabel(a2.label).toLowerCase()}`)].join(
|
|
87653
|
+
return [NAV_HINT, ...keyed.map((a2) => `[${a2.key}] ${shortLabel(a2.label).toLowerCase()}`)].join(
|
|
87654
|
+
" "
|
|
87655
|
+
);
|
|
87655
87656
|
});
|
|
87656
87657
|
let legend;
|
|
87657
87658
|
if (focus === "repos") {
|
|
@@ -87671,7 +87672,9 @@ var import_react5 = __toESM(require_react(), 1);
|
|
|
87671
87672
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
87672
87673
|
function FilterModal() {
|
|
87673
87674
|
const outputFilter = useCockpitStore((s) => s.outputFilter);
|
|
87674
|
-
const [severityDraft, setSeverityDraft] = (0, import_react5.useState)(
|
|
87675
|
+
const [severityDraft, setSeverityDraft] = (0, import_react5.useState)(
|
|
87676
|
+
outputFilter.severity
|
|
87677
|
+
);
|
|
87675
87678
|
const SEVERITIES = [void 0, "info", "warn", "error"];
|
|
87676
87679
|
use_input_default((input, key) => {
|
|
87677
87680
|
if (input === "s") {
|
|
@@ -87684,26 +87687,16 @@ function FilterModal() {
|
|
|
87684
87687
|
cockpitStore.getState().setActiveModal(null);
|
|
87685
87688
|
}
|
|
87686
87689
|
});
|
|
87687
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
87688
|
-
|
|
87689
|
-
{
|
|
87690
|
-
|
|
87691
|
-
|
|
87692
|
-
|
|
87693
|
-
|
|
87694
|
-
|
|
87695
|
-
|
|
87696
|
-
|
|
87697
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87698
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
|
|
87699
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: "Severity (s to cycle): " }),
|
|
87700
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "cyan", children: severityDraft ?? "all" })
|
|
87701
|
-
] }),
|
|
87702
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87703
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: "Enter = apply \xB7 Esc = cancel" })
|
|
87704
|
-
]
|
|
87705
|
-
}
|
|
87706
|
-
) });
|
|
87690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
|
|
87691
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, children: " Filter Output " }),
|
|
87692
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87693
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { children: [
|
|
87694
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: "Severity (s to cycle): " }),
|
|
87695
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: "cyan", children: severityDraft ?? "all" })
|
|
87696
|
+
] }),
|
|
87697
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: " " }),
|
|
87698
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: "Enter = apply \xB7 Esc = cancel" })
|
|
87699
|
+
] }) });
|
|
87707
87700
|
}
|
|
87708
87701
|
|
|
87709
87702
|
// src/cockpit/panes/SearchModal.tsx
|
|
@@ -87733,29 +87726,19 @@ function SearchModal() {
|
|
|
87733
87726
|
setQuery((prev) => prev + input);
|
|
87734
87727
|
}
|
|
87735
87728
|
});
|
|
87736
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
87737
|
-
|
|
87738
|
-
{
|
|
87739
|
-
|
|
87740
|
-
|
|
87741
|
-
|
|
87742
|
-
|
|
87743
|
-
|
|
87744
|
-
|
|
87745
|
-
|
|
87746
|
-
|
|
87747
|
-
|
|
87748
|
-
|
|
87749
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "cyan", children: [
|
|
87750
|
-
query,
|
|
87751
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "gray", children: "\u2588" })
|
|
87752
|
-
] })
|
|
87753
|
-
] }),
|
|
87754
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: " " }),
|
|
87755
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { dimColor: true, children: "Enter = apply \xB7 Esc = cancel \xB7 Backspace = delete" })
|
|
87756
|
-
]
|
|
87757
|
-
}
|
|
87758
|
-
) });
|
|
87729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
|
|
87730
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { bold: true, children: " Search Output " }),
|
|
87731
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: " " }),
|
|
87732
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { children: [
|
|
87733
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: "Query: " }),
|
|
87734
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "cyan", children: [
|
|
87735
|
+
query,
|
|
87736
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "gray", children: "\u2588" })
|
|
87737
|
+
] })
|
|
87738
|
+
] }),
|
|
87739
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: " " }),
|
|
87740
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { dimColor: true, children: "Enter = apply \xB7 Esc = cancel \xB7 Backspace = delete" })
|
|
87741
|
+
] }) });
|
|
87759
87742
|
}
|
|
87760
87743
|
|
|
87761
87744
|
// src/cockpit/panes/CommandModal.tsx
|
|
@@ -87910,9 +87893,7 @@ function useGlobalKeys(opts) {
|
|
|
87910
87893
|
return;
|
|
87911
87894
|
}
|
|
87912
87895
|
if (input === "e" && onOpenError) {
|
|
87913
|
-
const target = state.recentErrors.find(
|
|
87914
|
-
(er) => er.file && typeof er.line === "number"
|
|
87915
|
-
);
|
|
87896
|
+
const target = state.recentErrors.find((er) => er.file && typeof er.line === "number");
|
|
87916
87897
|
if (target?.file && typeof target.line === "number") {
|
|
87917
87898
|
onOpenError({
|
|
87918
87899
|
file: target.file,
|
|
@@ -87950,10 +87931,7 @@ function useGlobalKeys(opts) {
|
|
|
87950
87931
|
healthId: dispatch.healthId,
|
|
87951
87932
|
healthLabel: dispatch.healthLabel
|
|
87952
87933
|
});
|
|
87953
|
-
withMinHold(
|
|
87954
|
-
dispatch.promise,
|
|
87955
|
-
() => cockpitStore.getState().setActiveRemediation(null)
|
|
87956
|
-
);
|
|
87934
|
+
withMinHold(dispatch.promise, () => cockpitStore.getState().setActiveRemediation(null));
|
|
87957
87935
|
return;
|
|
87958
87936
|
}
|
|
87959
87937
|
}
|
|
@@ -90967,11 +90945,7 @@ async function devCommand(opts = {}) {
|
|
|
90967
90945
|
const builtinActions = buildBuiltinActions(config);
|
|
90968
90946
|
const actions = buildActionRegistry(
|
|
90969
90947
|
[...config.actions],
|
|
90970
|
-
[
|
|
90971
|
-
...builtinActions,
|
|
90972
|
-
...profile?.actions ?? [],
|
|
90973
|
-
...bootResult.actions ?? []
|
|
90974
|
-
]
|
|
90948
|
+
[...builtinActions, ...profile?.actions ?? [], ...bootResult.actions ?? []]
|
|
90975
90949
|
);
|
|
90976
90950
|
const [shell, shellFlag] = process.platform === "win32" ? ["cmd", "/c"] : ["/bin/sh", "-c"];
|
|
90977
90951
|
const highlightMatcher = compileHighlights(config.highlights);
|
|
@@ -91044,7 +91018,12 @@ async function devCommand(opts = {}) {
|
|
|
91044
91018
|
}
|
|
91045
91019
|
if (action.id.startsWith(BUILTIN_RESTART_PROCESS)) {
|
|
91046
91020
|
const procId = action.id.slice(BUILTIN_RESTART_PROCESS.length);
|
|
91047
|
-
store.appendOutput({
|
|
91021
|
+
store.appendOutput({
|
|
91022
|
+
ts: Date.now(),
|
|
91023
|
+
source: procId,
|
|
91024
|
+
severity: "info",
|
|
91025
|
+
text: `> restart ${procId}`
|
|
91026
|
+
});
|
|
91048
91027
|
await killSpawnedByTag(procId);
|
|
91049
91028
|
spawnProcessById(procId);
|
|
91050
91029
|
store.setFocus("output");
|
|
@@ -91338,10 +91317,7 @@ function renderWizardYaml(result) {
|
|
|
91338
91317
|
if (health.length > 0) blocks.push(health);
|
|
91339
91318
|
const actions = renderActions(result.actions);
|
|
91340
91319
|
if (actions.length > 0) blocks.push(actions);
|
|
91341
|
-
blocks.push([
|
|
91342
|
-
"notifications:",
|
|
91343
|
-
indent(`enabled: ${result.notifications.enabled}`, 1)
|
|
91344
|
-
]);
|
|
91320
|
+
blocks.push(["notifications:", indent(`enabled: ${result.notifications.enabled}`, 1)]);
|
|
91345
91321
|
if (result.profileLines && result.profileLines.length > 0) {
|
|
91346
91322
|
blocks.push([
|
|
91347
91323
|
"profile:",
|
|
@@ -91410,7 +91386,12 @@ function safeReadJson(p) {
|
|
|
91410
91386
|
}
|
|
91411
91387
|
}
|
|
91412
91388
|
function detectComposeFile(cwd) {
|
|
91413
|
-
for (const candidate of [
|
|
91389
|
+
for (const candidate of [
|
|
91390
|
+
"compose.yaml",
|
|
91391
|
+
"compose.yml",
|
|
91392
|
+
"docker-compose.yml",
|
|
91393
|
+
"docker-compose.yaml"
|
|
91394
|
+
]) {
|
|
91414
91395
|
if (fs11.existsSync(path15.join(cwd, candidate))) return candidate;
|
|
91415
91396
|
}
|
|
91416
91397
|
return void 0;
|
|
@@ -91448,7 +91429,10 @@ function detectRepoSuggestions(cwd, pkg) {
|
|
|
91448
91429
|
}
|
|
91449
91430
|
for (const glob of workspaceGlobs) {
|
|
91450
91431
|
for (const entry of expandSimpleGlob(cwd, glob)) {
|
|
91451
|
-
out.push({
|
|
91432
|
+
out.push({
|
|
91433
|
+
id: path15.basename(entry),
|
|
91434
|
+
path: path15.relative(cwd, path15.join(cwd, entry)) || "."
|
|
91435
|
+
});
|
|
91452
91436
|
}
|
|
91453
91437
|
}
|
|
91454
91438
|
const pnpmFile = path15.join(cwd, "pnpm-workspace.yaml");
|
|
@@ -91791,7 +91775,9 @@ async function promptHealthChecks(prompts, hints, hasDocker) {
|
|
|
91791
91775
|
].join("\n")
|
|
91792
91776
|
);
|
|
91793
91777
|
const out = [];
|
|
91794
|
-
let typeChoices = baseHealthTypeChoices(
|
|
91778
|
+
let typeChoices = baseHealthTypeChoices(
|
|
91779
|
+
Boolean(hints.composeFile && hints.composeServices.length > 0)
|
|
91780
|
+
);
|
|
91795
91781
|
if (!hasDocker) {
|
|
91796
91782
|
typeChoices = typeChoices.filter((c3) => c3.value !== "container-running");
|
|
91797
91783
|
}
|
|
@@ -91856,7 +91842,14 @@ async function promptOneHealthCheck(prompts, type, hints) {
|
|
|
91856
91842
|
})).trim();
|
|
91857
91843
|
idDefault = `${slugify(container)}-up`;
|
|
91858
91844
|
labelDefault = `Container \`${container}\` running`;
|
|
91859
|
-
typeArgs = {
|
|
91845
|
+
typeArgs = {
|
|
91846
|
+
type,
|
|
91847
|
+
container,
|
|
91848
|
+
id: "",
|
|
91849
|
+
label: "",
|
|
91850
|
+
severity: "error",
|
|
91851
|
+
remediation: { key: "", label: "", command: "" }
|
|
91852
|
+
};
|
|
91860
91853
|
break;
|
|
91861
91854
|
}
|
|
91862
91855
|
case "port-open": {
|
|
@@ -91865,7 +91858,15 @@ async function promptOneHealthCheck(prompts, type, hints) {
|
|
|
91865
91858
|
const port = portRaw ?? 0;
|
|
91866
91859
|
idDefault = `port-${port}-open`;
|
|
91867
91860
|
labelDefault = `Port ${port} open`;
|
|
91868
|
-
typeArgs = {
|
|
91861
|
+
typeArgs = {
|
|
91862
|
+
type,
|
|
91863
|
+
host,
|
|
91864
|
+
port,
|
|
91865
|
+
id: "",
|
|
91866
|
+
label: "",
|
|
91867
|
+
severity: "error",
|
|
91868
|
+
remediation: { key: "", label: "", command: "" }
|
|
91869
|
+
};
|
|
91869
91870
|
break;
|
|
91870
91871
|
}
|
|
91871
91872
|
case "http-ok": {
|
|
@@ -91877,7 +91878,14 @@ async function promptOneHealthCheck(prompts, type, hints) {
|
|
|
91877
91878
|
const pathPart = url.replace(/^https?:\/\/[^/]+/, "").replace(/^\//, "") || "root";
|
|
91878
91879
|
idDefault = `http-${slugify(pathPart)}`;
|
|
91879
91880
|
labelDefault = `GET ${url} returns 2xx`;
|
|
91880
|
-
typeArgs = {
|
|
91881
|
+
typeArgs = {
|
|
91882
|
+
type,
|
|
91883
|
+
url,
|
|
91884
|
+
id: "",
|
|
91885
|
+
label: "",
|
|
91886
|
+
severity: "error",
|
|
91887
|
+
remediation: { key: "", label: "", command: "" }
|
|
91888
|
+
};
|
|
91881
91889
|
break;
|
|
91882
91890
|
}
|
|
91883
91891
|
case "file-exists": {
|
|
@@ -91889,16 +91897,33 @@ async function promptOneHealthCheck(prompts, type, hints) {
|
|
|
91889
91897
|
const basename3 = filePath.split("/").filter(Boolean).pop() ?? filePath;
|
|
91890
91898
|
idDefault = `${slugify(basename3)}-exists`;
|
|
91891
91899
|
labelDefault = `\`${filePath}\` exists`;
|
|
91892
|
-
typeArgs = {
|
|
91900
|
+
typeArgs = {
|
|
91901
|
+
type,
|
|
91902
|
+
path: filePath,
|
|
91903
|
+
id: "",
|
|
91904
|
+
label: "",
|
|
91905
|
+
severity: "error",
|
|
91906
|
+
remediation: { key: "", label: "", command: "" }
|
|
91907
|
+
};
|
|
91893
91908
|
break;
|
|
91894
91909
|
}
|
|
91895
91910
|
case "exec-zero": {
|
|
91896
91911
|
explain(" The command runs once at startup. Exit code 0 = pass, anything else = fail.");
|
|
91897
|
-
const command = (await prompts.input({
|
|
91912
|
+
const command = (await prompts.input({
|
|
91913
|
+
message: "command",
|
|
91914
|
+
validate: (s) => s.trim().length > 0 ? true : "cannot be empty"
|
|
91915
|
+
})).trim();
|
|
91898
91916
|
const verb = slugify(command.split(/\s+/)[0] ?? "exec");
|
|
91899
91917
|
idDefault = `${verb}-ok`;
|
|
91900
91918
|
labelDefault = `\`${command.length > 40 ? command.slice(0, 37) + "\u2026" : command}\` exits 0`;
|
|
91901
|
-
typeArgs = {
|
|
91919
|
+
typeArgs = {
|
|
91920
|
+
type,
|
|
91921
|
+
command,
|
|
91922
|
+
id: "",
|
|
91923
|
+
label: "",
|
|
91924
|
+
severity: "error",
|
|
91925
|
+
remediation: { key: "", label: "", command: "" }
|
|
91926
|
+
};
|
|
91902
91927
|
break;
|
|
91903
91928
|
}
|
|
91904
91929
|
}
|
|
@@ -91922,7 +91947,11 @@ async function promptOneHealthCheck(prompts, type, hints) {
|
|
|
91922
91947
|
});
|
|
91923
91948
|
const typed = { ...typeArgs, id, label, severity };
|
|
91924
91949
|
blank();
|
|
91925
|
-
line(
|
|
91950
|
+
line(
|
|
91951
|
+
source_default.bold(
|
|
91952
|
+
" Remediation \u2014 what should pressing a key in the cockpit do when this check fails?"
|
|
91953
|
+
)
|
|
91954
|
+
);
|
|
91926
91955
|
explain(
|
|
91927
91956
|
[
|
|
91928
91957
|
" Three pieces:",
|
|
@@ -91977,7 +92006,15 @@ function defaultRemediationCommand(type, hints) {
|
|
|
91977
92006
|
return 'echo "edit cockpit.yaml to set the fix command"';
|
|
91978
92007
|
}
|
|
91979
92008
|
}
|
|
91980
|
-
var ACTION_SCRIPT_CANDIDATES = [
|
|
92009
|
+
var ACTION_SCRIPT_CANDIDATES = [
|
|
92010
|
+
"test",
|
|
92011
|
+
"build",
|
|
92012
|
+
"lint",
|
|
92013
|
+
"format",
|
|
92014
|
+
"typecheck",
|
|
92015
|
+
"type-check",
|
|
92016
|
+
"check"
|
|
92017
|
+
];
|
|
91981
92018
|
function defaultKeyFor(scriptName) {
|
|
91982
92019
|
const map = {
|
|
91983
92020
|
test: "t",
|
|
@@ -91997,9 +92034,7 @@ async function promptActions(prompts, hints) {
|
|
|
91997
92034
|
"from `processes` (long-running streams) and `health` (state-checked)."
|
|
91998
92035
|
].join("\n")
|
|
91999
92036
|
);
|
|
92000
|
-
const suggestionScripts = ACTION_SCRIPT_CANDIDATES.filter(
|
|
92001
|
-
(s) => hints.packageJsonScripts[s]
|
|
92002
|
-
);
|
|
92037
|
+
const suggestionScripts = ACTION_SCRIPT_CANDIDATES.filter((s) => hints.packageJsonScripts[s]);
|
|
92003
92038
|
const actions = [];
|
|
92004
92039
|
if (suggestionScripts.length > 0) {
|
|
92005
92040
|
blank();
|
|
@@ -92015,7 +92050,10 @@ async function promptActions(prompts, hints) {
|
|
|
92015
92050
|
const key = defaultKeyFor(s);
|
|
92016
92051
|
const keyHint = key ? ` [${key}]` : "";
|
|
92017
92052
|
return {
|
|
92018
|
-
name: `${s}${keyHint} \u2192 npm run ${s} (${hints.packageJsonScripts[s] ?? ""})`.slice(
|
|
92053
|
+
name: `${s}${keyHint} \u2192 npm run ${s} (${hints.packageJsonScripts[s] ?? ""})`.slice(
|
|
92054
|
+
0,
|
|
92055
|
+
80
|
|
92056
|
+
),
|
|
92019
92057
|
value: s,
|
|
92020
92058
|
checked: true
|
|
92021
92059
|
};
|
|
@@ -92106,7 +92144,9 @@ async function runInitWizard(opts) {
|
|
|
92106
92144
|
line(source_default.dim(" 8. Notifications \u2014 native OS toasts on state changes"));
|
|
92107
92145
|
blank();
|
|
92108
92146
|
line(" Anything you skip you can add later by hand-editing cockpit.yaml.");
|
|
92109
|
-
line(
|
|
92147
|
+
line(
|
|
92148
|
+
` Press ${source_default.cyan("Ctrl-C")} to quit; press ${source_default.cyan("enter")} to accept any default.`
|
|
92149
|
+
);
|
|
92110
92150
|
blank();
|
|
92111
92151
|
const proceed = await prompts.confirm({ message: "Ready?", default: true });
|
|
92112
92152
|
if (!proceed) {
|
|
@@ -92268,14 +92308,18 @@ dev-cockpit init-config: wrote ${target}
|
|
|
92268
92308
|
try {
|
|
92269
92309
|
await doctorCommand({ config: target, profile: opts.profile });
|
|
92270
92310
|
} catch (err) {
|
|
92271
|
-
process.stderr.write(
|
|
92311
|
+
process.stderr.write(
|
|
92312
|
+
`
|
|
92272
92313
|
doctor failed: ${err instanceof Error ? err.message : String(err)}
|
|
92273
|
-
`
|
|
92314
|
+
`
|
|
92315
|
+
);
|
|
92274
92316
|
}
|
|
92275
92317
|
}
|
|
92276
92318
|
process.stdout.write("\nNext:\n");
|
|
92277
92319
|
process.stdout.write(" \u2022 Edit cockpit.yaml any time, then re-run `dev-cockpit doctor`.\n");
|
|
92278
|
-
process.stdout.write(
|
|
92320
|
+
process.stdout.write(
|
|
92321
|
+
" \u2022 Run `dev-cockpit dev` to launch the cockpit (Tab/arrows cycle panes, q quits).\n"
|
|
92322
|
+
);
|
|
92279
92323
|
process.stdout.write(" \u2022 The Help tab inside the cockpit has the full docs.\n");
|
|
92280
92324
|
} else {
|
|
92281
92325
|
process.stdout.write(" Run `dev-cockpit doctor` to verify the config loads cleanly.\n");
|
|
@@ -92350,10 +92394,14 @@ function validateMountManifest(filePath, raw) {
|
|
|
92350
92394
|
// src/mount/compose.ts
|
|
92351
92395
|
function renderDockerOverlay(mounts, opts) {
|
|
92352
92396
|
const lines = [];
|
|
92353
|
-
lines.push(
|
|
92397
|
+
lines.push(
|
|
92398
|
+
opts.banner ?? "# Generated by `dev-cockpit mount`. Do not edit by hand \u2014 re-run the command."
|
|
92399
|
+
);
|
|
92354
92400
|
lines.push("services:");
|
|
92355
92401
|
lines.push(` ${opts.service}:`);
|
|
92356
|
-
const binds = mounts.filter(
|
|
92402
|
+
const binds = mounts.filter(
|
|
92403
|
+
(m) => m.kind !== "symlink-only" && typeof m.containerPath === "string"
|
|
92404
|
+
);
|
|
92357
92405
|
if (binds.length === 0) {
|
|
92358
92406
|
lines.push(" volumes: []");
|
|
92359
92407
|
} else {
|
|
@@ -92485,23 +92533,19 @@ function detectBrokenSymlinks(workspaceRoot, mounts, strategy) {
|
|
|
92485
92533
|
async function readGitInfo(hostPath) {
|
|
92486
92534
|
try {
|
|
92487
92535
|
let branchOut = "";
|
|
92488
|
-
const branchHandle = spawnStream(
|
|
92489
|
-
|
|
92490
|
-
["-C", hostPath, "rev-parse", "--abbrev-ref", "HEAD"],
|
|
92491
|
-
{ onStdout: (line2) => {
|
|
92536
|
+
const branchHandle = spawnStream("git", ["-C", hostPath, "rev-parse", "--abbrev-ref", "HEAD"], {
|
|
92537
|
+
onStdout: (line2) => {
|
|
92492
92538
|
branchOut += line2;
|
|
92493
|
-
}
|
|
92494
|
-
);
|
|
92539
|
+
}
|
|
92540
|
+
});
|
|
92495
92541
|
const branchCode = await branchHandle.exitCode;
|
|
92496
92542
|
if (branchCode !== 0) return null;
|
|
92497
92543
|
let statusOut = "";
|
|
92498
|
-
const statusHandle = spawnStream(
|
|
92499
|
-
|
|
92500
|
-
["-C", hostPath, "status", "--porcelain"],
|
|
92501
|
-
{ onStdout: (line2) => {
|
|
92544
|
+
const statusHandle = spawnStream("git", ["-C", hostPath, "status", "--porcelain"], {
|
|
92545
|
+
onStdout: (line2) => {
|
|
92502
92546
|
statusOut += line2;
|
|
92503
|
-
}
|
|
92504
|
-
);
|
|
92547
|
+
}
|
|
92548
|
+
});
|
|
92505
92549
|
await statusHandle.exitCode;
|
|
92506
92550
|
return {
|
|
92507
92551
|
branch: branchOut.trim() || "?",
|
|
@@ -92543,20 +92587,18 @@ async function resolveContext(opts) {
|
|
|
92543
92587
|
throw err;
|
|
92544
92588
|
}
|
|
92545
92589
|
if (!fs15.existsSync(configPath)) {
|
|
92546
|
-
process.stderr.write(
|
|
92547
|
-
|
|
92548
|
-
`
|
|
92549
|
-
);
|
|
92590
|
+
process.stderr.write(`dev-cockpit mount: cockpit.yaml at ${configPath} doesn't exist.
|
|
92591
|
+
`);
|
|
92550
92592
|
process.exit(1);
|
|
92551
92593
|
}
|
|
92552
92594
|
const config = loadConfig(configPath, {
|
|
92553
92595
|
configSchemaExt: profile?.configSchemaExt,
|
|
92554
92596
|
profileKey: profile?.appName
|
|
92555
92597
|
});
|
|
92556
|
-
const explicitService = opts.service ?? config.docker?.services?.[0]?.name;
|
|
92598
|
+
const explicitService = opts.service ?? config.mount.service ?? config.docker?.services?.[0]?.name;
|
|
92557
92599
|
if (!explicitService) {
|
|
92558
92600
|
process.stderr.write(
|
|
92559
|
-
"dev-cockpit mount: no target service. Pass --service <name
|
|
92601
|
+
"dev-cockpit mount: no target service. Pass --service <name>, set mount.service in cockpit.yaml, or set docker.services in cockpit.yaml.\n"
|
|
92560
92602
|
);
|
|
92561
92603
|
process.exit(1);
|
|
92562
92604
|
}
|
|
@@ -92584,46 +92626,188 @@ var stdoutSink = (line2) => process.stdout.write(`${line2}
|
|
|
92584
92626
|
`);
|
|
92585
92627
|
var stderrSink = (line2) => process.stderr.write(`${line2}
|
|
92586
92628
|
`);
|
|
92587
|
-
function
|
|
92588
|
-
|
|
92589
|
-
const
|
|
92590
|
-
|
|
92591
|
-
|
|
92592
|
-
|
|
92629
|
+
function mountLabel(m) {
|
|
92630
|
+
const fallbackName = m.containerPath ?? (m.kind === "symlink-only" ? `(symlink) ${m.hostPath}` : m.hostPath);
|
|
92631
|
+
const name = m.meta?.["name"] ?? fallbackName;
|
|
92632
|
+
const type = m.meta?.["type"];
|
|
92633
|
+
return type ? `${name} (${type})` : name;
|
|
92634
|
+
}
|
|
92635
|
+
function isUnmatched(m) {
|
|
92636
|
+
return m.meta?.["unmatched"] === true;
|
|
92637
|
+
}
|
|
92638
|
+
var CUSTOM_PATH_SENTINEL = "__custom__";
|
|
92639
|
+
async function pickSourceForMount(m, prompts) {
|
|
92640
|
+
const alts = m.alternativeSources ?? [];
|
|
92641
|
+
const choices = [
|
|
92642
|
+
...alts.map((s) => ({ name: s, value: s })),
|
|
92643
|
+
{ name: "Custom path...", value: CUSTOM_PATH_SENTINEL }
|
|
92644
|
+
];
|
|
92645
|
+
const chosen = await prompts.select({
|
|
92646
|
+
message: `Source for ${mountLabel(m)}:`,
|
|
92647
|
+
choices,
|
|
92648
|
+
default: alts.includes(m.hostPath) ? m.hostPath : void 0
|
|
92593
92649
|
});
|
|
92650
|
+
if (chosen !== CUSTOM_PATH_SENTINEL) return chosen;
|
|
92651
|
+
return (await prompts.input({
|
|
92652
|
+
message: "Host path (absolute):",
|
|
92653
|
+
validate: (v) => v.trim().length > 0 && path20.isAbsolute(v.trim()) ? true : "must be an absolute path"
|
|
92654
|
+
})).trim();
|
|
92594
92655
|
}
|
|
92595
92656
|
async function pickMounts(candidates) {
|
|
92596
|
-
const { checkbox } = await import("@inquirer/prompts");
|
|
92597
|
-
const
|
|
92598
|
-
|
|
92599
|
-
|
|
92600
|
-
const
|
|
92601
|
-
|
|
92602
|
-
|
|
92603
|
-
|
|
92604
|
-
|
|
92605
|
-
|
|
92606
|
-
|
|
92607
|
-
|
|
92657
|
+
const { checkbox, confirm, input, select } = await import("@inquirer/prompts");
|
|
92658
|
+
const prompts = { select, input };
|
|
92659
|
+
let selected = [];
|
|
92660
|
+
if (candidates.length > 0) {
|
|
92661
|
+
const choices = candidates.map((m) => {
|
|
92662
|
+
const unmatched = isUnmatched(m);
|
|
92663
|
+
const suffix = unmatched ? " (no source found \u2014 pick one)" : ` ${m.hostPath}`;
|
|
92664
|
+
return {
|
|
92665
|
+
name: `${mountLabel(m)}${suffix}`,
|
|
92666
|
+
value: m,
|
|
92667
|
+
checked: !unmatched
|
|
92668
|
+
};
|
|
92669
|
+
});
|
|
92670
|
+
selected = await checkbox({ message: "Select mounts to apply:", choices });
|
|
92671
|
+
}
|
|
92672
|
+
const unmatchedRows = selected.filter(isUnmatched);
|
|
92673
|
+
const matchedWithAlts = selected.filter(
|
|
92674
|
+
(m) => !isUnmatched(m) && (m.alternativeSources?.length ?? 0) > 0
|
|
92675
|
+
);
|
|
92676
|
+
for (const m of unmatchedRows) {
|
|
92677
|
+
const chosen = await pickSourceForMount(m, prompts);
|
|
92678
|
+
const next = { ...m, hostPath: chosen };
|
|
92679
|
+
if (next.meta && "unmatched" in next.meta) {
|
|
92680
|
+
const cleaned = { ...next.meta };
|
|
92681
|
+
delete cleaned["unmatched"];
|
|
92682
|
+
next.meta = cleaned;
|
|
92683
|
+
}
|
|
92684
|
+
const idx = selected.indexOf(m);
|
|
92685
|
+
if (idx >= 0) selected[idx] = next;
|
|
92686
|
+
}
|
|
92687
|
+
const overridable = matchedWithAlts;
|
|
92688
|
+
if (overridable.length > 0) {
|
|
92689
|
+
const wantOverride = await confirm({
|
|
92690
|
+
message: "Override the source dir for any of the selected mounts?",
|
|
92691
|
+
default: false
|
|
92692
|
+
});
|
|
92693
|
+
if (wantOverride) {
|
|
92694
|
+
const toEdit = await checkbox({
|
|
92695
|
+
message: "Pick the mounts whose source you want to change:",
|
|
92696
|
+
choices: overridable.map((m) => ({
|
|
92697
|
+
name: `${mountLabel(m)} (current: ${m.hostPath})`,
|
|
92698
|
+
value: m,
|
|
92699
|
+
checked: false
|
|
92700
|
+
}))
|
|
92701
|
+
});
|
|
92702
|
+
for (const m of toEdit) {
|
|
92703
|
+
const chosen = await pickSourceForMount(m, prompts);
|
|
92704
|
+
const idx = selected.indexOf(m);
|
|
92705
|
+
if (idx >= 0) selected[idx] = { ...m, hostPath: chosen };
|
|
92706
|
+
}
|
|
92707
|
+
}
|
|
92708
|
+
}
|
|
92709
|
+
const knownContainerPaths = Array.from(
|
|
92710
|
+
new Set(
|
|
92711
|
+
candidates.map((c3) => c3.containerPath).filter((p) => typeof p === "string" && p.length > 0)
|
|
92712
|
+
)
|
|
92713
|
+
);
|
|
92714
|
+
const knownHostPaths = Array.from(
|
|
92715
|
+
new Set(candidates.flatMap((c3) => c3.alternativeSources ?? []))
|
|
92716
|
+
);
|
|
92717
|
+
while (await confirm({
|
|
92718
|
+
message: candidates.length === 0 ? "Add a custom mount?" : "Add another (custom) mount?",
|
|
92719
|
+
default: false
|
|
92720
|
+
})) {
|
|
92721
|
+
let hostPath;
|
|
92722
|
+
if (knownHostPaths.length > 0) {
|
|
92723
|
+
const picked = await select({
|
|
92724
|
+
message: "Host path:",
|
|
92725
|
+
choices: [
|
|
92726
|
+
...knownHostPaths.map((s) => ({ name: s, value: s })),
|
|
92727
|
+
{ name: "Custom path...", value: CUSTOM_PATH_SENTINEL }
|
|
92728
|
+
]
|
|
92729
|
+
});
|
|
92730
|
+
if (picked === CUSTOM_PATH_SENTINEL) {
|
|
92731
|
+
hostPath = (await input({
|
|
92732
|
+
message: "Host path (absolute):",
|
|
92733
|
+
validate: (v) => v.trim().length > 0 && path20.isAbsolute(v.trim()) ? true : "must be an absolute path"
|
|
92734
|
+
})).trim();
|
|
92735
|
+
} else {
|
|
92736
|
+
hostPath = picked;
|
|
92737
|
+
}
|
|
92738
|
+
} else {
|
|
92739
|
+
hostPath = (await input({
|
|
92740
|
+
message: "Host path (absolute):",
|
|
92741
|
+
validate: (v) => v.trim().length > 0 && path20.isAbsolute(v.trim()) ? true : "must be an absolute path"
|
|
92742
|
+
})).trim();
|
|
92743
|
+
}
|
|
92744
|
+
let containerPath;
|
|
92745
|
+
if (knownContainerPaths.length > 0) {
|
|
92746
|
+
const picked = await select({
|
|
92747
|
+
message: "Container path:",
|
|
92748
|
+
choices: [
|
|
92749
|
+
...knownContainerPaths.map((p) => ({ name: p, value: p })),
|
|
92750
|
+
{ name: "Custom path...", value: CUSTOM_PATH_SENTINEL }
|
|
92751
|
+
]
|
|
92752
|
+
});
|
|
92753
|
+
if (picked === CUSTOM_PATH_SENTINEL) {
|
|
92754
|
+
containerPath = (await input({
|
|
92755
|
+
message: "Container path (absolute):",
|
|
92756
|
+
validate: (v) => v.trim().length > 0 && path20.isAbsolute(v.trim()) ? true : "must be an absolute path"
|
|
92757
|
+
})).trim();
|
|
92758
|
+
} else {
|
|
92759
|
+
containerPath = picked;
|
|
92760
|
+
}
|
|
92761
|
+
} else {
|
|
92762
|
+
containerPath = (await input({
|
|
92763
|
+
message: "Container path (absolute):",
|
|
92764
|
+
validate: (v) => v.trim().length > 0 && path20.isAbsolute(v.trim()) ? true : "must be an absolute path"
|
|
92765
|
+
})).trim();
|
|
92766
|
+
}
|
|
92767
|
+
const name = (await input({
|
|
92768
|
+
message: "Name (optional, used for status table + log lines):"
|
|
92769
|
+
})).trim();
|
|
92770
|
+
selected.push({
|
|
92771
|
+
hostPath,
|
|
92772
|
+
containerPath,
|
|
92773
|
+
kind: "bind",
|
|
92774
|
+
...name ? { meta: { name } } : {}
|
|
92775
|
+
});
|
|
92776
|
+
}
|
|
92777
|
+
return selected;
|
|
92608
92778
|
}
|
|
92609
92779
|
async function mountCommand(opts = {}) {
|
|
92610
92780
|
const ctx = await resolveContext(opts);
|
|
92611
|
-
const {
|
|
92612
|
-
|
|
92613
|
-
|
|
92614
|
-
|
|
92615
|
-
|
|
92616
|
-
|
|
92617
|
-
|
|
92618
|
-
|
|
92781
|
+
const {
|
|
92782
|
+
workspaceRoot,
|
|
92783
|
+
appName,
|
|
92784
|
+
service,
|
|
92785
|
+
configMounts,
|
|
92786
|
+
providerMounts,
|
|
92787
|
+
overlayPath,
|
|
92788
|
+
manifestPath: manifestPath2,
|
|
92789
|
+
profile
|
|
92790
|
+
} = ctx;
|
|
92791
|
+
const merged = mergeMounts(configMounts, providerMounts);
|
|
92619
92792
|
let selected;
|
|
92620
92793
|
if (opts.quiet || configMounts.length > 0 && providerMounts.length === 0) {
|
|
92794
|
+
if (merged.length === 0) {
|
|
92795
|
+
process.stdout.write(
|
|
92796
|
+
"dev-cockpit mount: no mount candidates from config.mounts[] or profile.mountCandidatesProvider.\n"
|
|
92797
|
+
);
|
|
92798
|
+
return;
|
|
92799
|
+
}
|
|
92621
92800
|
selected = merged;
|
|
92622
92801
|
if (opts.quiet) {
|
|
92623
92802
|
process.stdout.write(`dev-cockpit mount: applying all ${selected.length} candidate(s).
|
|
92624
92803
|
`);
|
|
92625
92804
|
}
|
|
92626
92805
|
} else {
|
|
92806
|
+
if (merged.length === 0) {
|
|
92807
|
+
process.stdout.write(
|
|
92808
|
+
"dev-cockpit mount: no mount candidates discovered. You can add custom mounts interactively below, or Ctrl-C to bail.\n"
|
|
92809
|
+
);
|
|
92810
|
+
}
|
|
92627
92811
|
selected = await pickMounts(merged);
|
|
92628
92812
|
if (selected.length === 0) {
|
|
92629
92813
|
process.stdout.write("dev-cockpit mount: nothing selected; nothing to apply.\n");
|
|
@@ -92656,7 +92840,8 @@ async function mountCommand(opts = {}) {
|
|
|
92656
92840
|
`
|
|
92657
92841
|
);
|
|
92658
92842
|
}
|
|
92659
|
-
for (const p of report.skipped)
|
|
92843
|
+
for (const p of report.skipped)
|
|
92844
|
+
process.stdout.write(`dev-cockpit mount: skipped (could not replace) \u2192 ${p}
|
|
92660
92845
|
`);
|
|
92661
92846
|
}
|
|
92662
92847
|
if (profile?.onMountApply) {
|
|
@@ -92798,8 +92983,10 @@ async function migrateConfigCommand(opts = {}) {
|
|
|
92798
92983
|
}
|
|
92799
92984
|
const fromVersion = raw["version"];
|
|
92800
92985
|
if (fromVersion === CONFIG_VERSION) {
|
|
92801
|
-
process.stdout.write(
|
|
92802
|
-
`
|
|
92986
|
+
process.stdout.write(
|
|
92987
|
+
`dev-cockpit migrate-config: already at v${CONFIG_VERSION}; nothing to do.
|
|
92988
|
+
`
|
|
92989
|
+
);
|
|
92803
92990
|
return;
|
|
92804
92991
|
}
|
|
92805
92992
|
if (fromVersion > CONFIG_VERSION) {
|
|
@@ -92851,24 +93038,32 @@ function buildCli(opts = {}) {
|
|
|
92851
93038
|
const program2 = new Command();
|
|
92852
93039
|
const profile = opts.profile;
|
|
92853
93040
|
const appName = profile?.appName ?? "dev-cockpit";
|
|
92854
|
-
program2.name(appName).description(
|
|
92855
|
-
profile ? `${appName} \u2014 built on dev-cockpit` : "Generic terminal UI dev cockpit"
|
|
92856
|
-
).version(readPackageVersion(), "-V, --version", "Output the version number");
|
|
93041
|
+
program2.name(appName).description(profile ? `${appName} \u2014 built on dev-cockpit` : "Generic terminal UI dev cockpit").version(readPackageVersion(), "-V, --version", "Output the version number");
|
|
92857
93042
|
if (profile?.setupCli) {
|
|
92858
93043
|
profile.setupCli(program2);
|
|
92859
93044
|
}
|
|
92860
93045
|
if (!hasCommand(program2, "dev")) {
|
|
92861
|
-
program2.command("dev").description("Boot the three-pane TUI (Repos / Output / Health / Help)").option(
|
|
93046
|
+
program2.command("dev").description("Boot the three-pane TUI (Repos / Output / Health / Help)").option(
|
|
93047
|
+
"-c, --config <path>",
|
|
93048
|
+
"Path to cockpit.yaml (default: <cwd>/cockpit.yaml or registered via `link`)"
|
|
93049
|
+
).action(async (cmdOpts) => {
|
|
92862
93050
|
await devCommand({ config: cmdOpts.config, profile });
|
|
92863
93051
|
});
|
|
92864
93052
|
}
|
|
92865
93053
|
if (!hasCommand(program2, "doctor")) {
|
|
92866
|
-
program2.command("doctor").description("Run all health checks once and print a status table").option(
|
|
93054
|
+
program2.command("doctor").description("Run all health checks once and print a status table").option(
|
|
93055
|
+
"-c, --config <path>",
|
|
93056
|
+
"Path to cockpit.yaml (default: <cwd>/cockpit.yaml or registered via `link`)"
|
|
93057
|
+
).action(async (cmdOpts) => {
|
|
92867
93058
|
await doctorCommand({ config: cmdOpts.config, profile });
|
|
92868
93059
|
});
|
|
92869
93060
|
}
|
|
92870
93061
|
if (!hasCommand(program2, "init-config")) {
|
|
92871
|
-
program2.command("init-config").description("Write a starter cockpit.yaml in the current directory").option("-f, --force", "Overwrite an existing cockpit.yaml without prompting", false).option("--with-docker", "Include an uncommented docker block (static template only)", false).option(
|
|
93062
|
+
program2.command("init-config").description("Write a starter cockpit.yaml in the current directory").option("-f, --force", "Overwrite an existing cockpit.yaml without prompting", false).option("--with-docker", "Include an uncommented docker block (static template only)", false).option(
|
|
93063
|
+
"-i, --interactive",
|
|
93064
|
+
"Walk through prompts to populate the file (skips static template)",
|
|
93065
|
+
false
|
|
93066
|
+
).option("-o, --output <path>", "Write the file to this path instead of <cwd>/cockpit.yaml").action(
|
|
92872
93067
|
async (cmdOpts) => {
|
|
92873
93068
|
await initConfigCommand({
|
|
92874
93069
|
force: cmdOpts.force ?? false,
|
|
@@ -92883,42 +93078,52 @@ function buildCli(opts = {}) {
|
|
|
92883
93078
|
}
|
|
92884
93079
|
if (!hasCommand(program2, "link")) {
|
|
92885
93080
|
const linkCmd = program2.command("link").description("Register the current directory as using a cockpit.yaml that lives elsewhere").argument("<config-path>", "Path to the cockpit.yaml to associate with this directory").action(async (configPath) => {
|
|
92886
|
-
const { linkAddCommand } = await import("./link-
|
|
93081
|
+
const { linkAddCommand } = await import("./link-Y7OFHOUP.js");
|
|
92887
93082
|
linkAddCommand({ configPath });
|
|
92888
93083
|
});
|
|
92889
93084
|
linkCmd.command("list").description("Print all registered project \u2192 config mappings").action(async () => {
|
|
92890
|
-
const { linkListCommand } = await import("./link-
|
|
93085
|
+
const { linkListCommand } = await import("./link-Y7OFHOUP.js");
|
|
92891
93086
|
linkListCommand();
|
|
92892
93087
|
});
|
|
92893
93088
|
linkCmd.command("remove").description("Unregister the current directory from the manifest").action(async () => {
|
|
92894
|
-
const { linkRemoveCommand } = await import("./link-
|
|
93089
|
+
const { linkRemoveCommand } = await import("./link-Y7OFHOUP.js");
|
|
92895
93090
|
linkRemoveCommand();
|
|
92896
93091
|
});
|
|
92897
93092
|
}
|
|
92898
93093
|
if (!hasCommand(program2, "mount")) {
|
|
92899
|
-
const mountCmd = program2.command("mount").description(
|
|
92900
|
-
|
|
92901
|
-
|
|
92902
|
-
|
|
92903
|
-
|
|
92904
|
-
|
|
93094
|
+
const mountCmd = program2.command("mount").description(
|
|
93095
|
+
`Apply a docker-compose bind-mount overlay (interactive picker by default)
|
|
93096
|
+
|
|
93097
|
+
This creates a docker-compose overlay file. The location of the overlay file is configurable in the cockpit.yaml file. You must then include the overlay file in your compose file as a wildcard include. eg. \`docker-compose.yml -f docker/compose/web/docker-compose.dev-link.yml\``
|
|
93098
|
+
).option(
|
|
93099
|
+
"-c, --config <path>",
|
|
93100
|
+
"Path to cockpit.yaml (default: <cwd>/cockpit.yaml or registered via `link`)"
|
|
93101
|
+
).option("-s, --service <name>", "Target compose service (default: first in docker.services)").option("-q, --quiet", "Skip the interactive picker; apply all candidates").action(async (cmdOpts) => {
|
|
92905
93102
|
await mountCommand({
|
|
92906
93103
|
config: cmdOpts.config,
|
|
92907
93104
|
service: cmdOpts.service,
|
|
92908
93105
|
quiet: cmdOpts.quiet ?? false,
|
|
92909
|
-
exclude: cmdOpts.exclude ?? [],
|
|
92910
93106
|
profile
|
|
92911
93107
|
});
|
|
92912
93108
|
});
|
|
92913
|
-
mountCmd.command("status").description("Show active mounts with branch, dirty, and broken-symlink status").option(
|
|
93109
|
+
mountCmd.command("status").description("Show active mounts with branch, dirty, and broken-symlink status").option(
|
|
93110
|
+
"-c, --config <path>",
|
|
93111
|
+
"Path to cockpit.yaml (default: <cwd>/cockpit.yaml or registered via `link`)"
|
|
93112
|
+
).action(async (cmdOpts) => {
|
|
92914
93113
|
await mountStatusCommand({ config: cmdOpts.config, profile });
|
|
92915
93114
|
});
|
|
92916
|
-
mountCmd.command("clear").description("Remove the overlay, manifest, and managed symlinks; runs profile.onMountClear").option(
|
|
93115
|
+
mountCmd.command("clear").description("Remove the overlay, manifest, and managed symlinks; runs profile.onMountClear").option(
|
|
93116
|
+
"-c, --config <path>",
|
|
93117
|
+
"Path to cockpit.yaml (default: <cwd>/cockpit.yaml or registered via `link`)"
|
|
93118
|
+
).action(async (cmdOpts) => {
|
|
92917
93119
|
await mountClearCommand({ config: cmdOpts.config, profile });
|
|
92918
93120
|
});
|
|
92919
93121
|
}
|
|
92920
93122
|
if (!hasCommand(program2, "migrate-config")) {
|
|
92921
|
-
program2.command("migrate-config").description("Rewrite cockpit.yaml at the current CONFIG_VERSION").option(
|
|
93123
|
+
program2.command("migrate-config").description("Rewrite cockpit.yaml at the current CONFIG_VERSION").option(
|
|
93124
|
+
"-c, --config <path>",
|
|
93125
|
+
"Path to cockpit.yaml (default: <cwd>/cockpit.yaml or registered via `link`)"
|
|
93126
|
+
).option("--dry-run", "Print the migrated YAML to stdout instead of writing").action(async (cmdOpts) => {
|
|
92922
93127
|
await migrateConfigCommand({ config: cmdOpts.config, dryRun: cmdOpts.dryRun });
|
|
92923
93128
|
});
|
|
92924
93129
|
}
|