dev-cockpit 0.1.0 → 0.2.1

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.
Files changed (140) hide show
  1. package/README.md +64 -29
  2. package/bin/dev-cockpit.mjs +26 -4
  3. package/dist/actions/builtin.d.ts +25 -0
  4. package/dist/actions/builtin.d.ts.map +1 -0
  5. package/dist/actions/dispatch.d.ts +21 -0
  6. package/dist/actions/dispatch.d.ts.map +1 -0
  7. package/dist/actions/registry.d.ts +11 -0
  8. package/dist/actions/registry.d.ts.map +1 -0
  9. package/dist/actions/types.d.ts +76 -0
  10. package/dist/actions/types.d.ts.map +1 -0
  11. package/dist/buildCli.d.ts.map +1 -1
  12. package/dist/chunk-6XGHLLYT.js +46 -0
  13. package/dist/chunk-6XGHLLYT.js.map +7 -0
  14. package/dist/chunk-Q6677JQF.js +32609 -0
  15. package/dist/chunk-Q6677JQF.js.map +7 -0
  16. package/dist/chunk-VN6UILQW.js +1460 -0
  17. package/dist/chunk-VN6UILQW.js.map +7 -0
  18. package/dist/cockpit/Cockpit.d.ts +6 -0
  19. package/dist/cockpit/Cockpit.d.ts.map +1 -1
  20. package/dist/cockpit/Footer.d.ts +6 -4
  21. package/dist/cockpit/Footer.d.ts.map +1 -1
  22. package/dist/cockpit/TabBar.d.ts.map +1 -1
  23. package/dist/cockpit/hooks/useGlobalKeys.d.ts +15 -15
  24. package/dist/cockpit/hooks/useGlobalKeys.d.ts.map +1 -1
  25. package/dist/cockpit/hooks/useTerminalWidth.d.ts +12 -0
  26. package/dist/cockpit/hooks/useTerminalWidth.d.ts.map +1 -0
  27. package/dist/cockpit/panes/CommandModal.d.ts +18 -0
  28. package/dist/cockpit/panes/CommandModal.d.ts.map +1 -0
  29. package/dist/cockpit/panes/Help.d.ts.map +1 -1
  30. package/dist/cockpit/panes/Output.d.ts +7 -0
  31. package/dist/cockpit/panes/Output.d.ts.map +1 -1
  32. package/dist/cockpit/panes/Repos.d.ts.map +1 -1
  33. package/dist/cockpit/state/store.d.ts +14 -11
  34. package/dist/cockpit/state/store.d.ts.map +1 -1
  35. package/dist/cockpit/tab-state.d.ts +12 -0
  36. package/dist/cockpit/tab-state.d.ts.map +1 -1
  37. package/dist/commands/dev.d.ts.map +1 -1
  38. package/dist/commands/init-config-wizard.d.ts +103 -2
  39. package/dist/commands/init-config-wizard.d.ts.map +1 -1
  40. package/dist/commands/init-config.d.ts.map +1 -1
  41. package/dist/commands/migrate-config.d.ts +18 -0
  42. package/dist/commands/migrate-config.d.ts.map +1 -0
  43. package/dist/commands/mount.d.ts +17 -32
  44. package/dist/commands/mount.d.ts.map +1 -1
  45. package/dist/core/config.d.ts +73 -5
  46. package/dist/core/config.d.ts.map +1 -1
  47. package/dist/core/migrations.d.ts +33 -0
  48. package/dist/core/migrations.d.ts.map +1 -0
  49. package/dist/core/subprocess.d.ts +20 -0
  50. package/dist/core/subprocess.d.ts.map +1 -1
  51. package/dist/core/types.d.ts +36 -12
  52. package/dist/core/types.d.ts.map +1 -1
  53. package/dist/devtools-YXMW6JJ6.js +3720 -0
  54. package/dist/devtools-YXMW6JJ6.js.map +7 -0
  55. package/dist/docker/highlights.d.ts +14 -4
  56. package/dist/docker/highlights.d.ts.map +1 -1
  57. package/dist/docker/logs.d.ts +3 -2
  58. package/dist/docker/logs.d.ts.map +1 -1
  59. package/dist/health/builtin.d.ts.map +1 -1
  60. package/dist/index.d.ts +14 -3
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +92837 -53
  63. package/dist/index.js.map +7 -0
  64. package/dist/ink.js +38 -1
  65. package/dist/ink.js.map +7 -0
  66. package/dist/mount/compose.d.ts +21 -0
  67. package/dist/mount/compose.d.ts.map +1 -0
  68. package/dist/mount/discovery.d.ts +35 -0
  69. package/dist/mount/discovery.d.ts.map +1 -0
  70. package/dist/mount/git-status.d.ts +12 -0
  71. package/dist/mount/git-status.d.ts.map +1 -0
  72. package/dist/mount/manifest.d.ts +16 -0
  73. package/dist/mount/manifest.d.ts.map +1 -0
  74. package/dist/mount/symlinks.d.ts +30 -0
  75. package/dist/mount/symlinks.d.ts.map +1 -0
  76. package/dist/mount/types.d.ts +60 -0
  77. package/dist/mount/types.d.ts.map +1 -0
  78. package/dist/react.js +35 -1
  79. package/dist/react.js.map +7 -0
  80. package/dist/runCockpit.d.ts +3 -0
  81. package/dist/runCockpit.d.ts.map +1 -1
  82. package/docs/commands.md +29 -16
  83. package/docs/config-reference.md +115 -11
  84. package/docs/getting-started.md +9 -6
  85. package/docs/index.md +5 -1
  86. package/docs/init-config.md +34 -8
  87. package/docs/mount.md +198 -25
  88. package/docs/notifications.md +14 -13
  89. package/docs/panes.md +36 -15
  90. package/docs/processes.md +42 -0
  91. package/package.json +93 -90
  92. package/dist/buildCli.js +0 -107
  93. package/dist/cli.js +0 -2
  94. package/dist/cockpit/Cockpit.js +0 -73
  95. package/dist/cockpit/Footer.js +0 -33
  96. package/dist/cockpit/TabBar.js +0 -12
  97. package/dist/cockpit/help/content.js +0 -22
  98. package/dist/cockpit/help/loader.js +0 -118
  99. package/dist/cockpit/help/renderer.js +0 -35
  100. package/dist/cockpit/help/types.js +0 -1
  101. package/dist/cockpit/hooks/useCockpitStore.js +0 -5
  102. package/dist/cockpit/hooks/useGlobalKeys.js +0 -173
  103. package/dist/cockpit/panes/FilterModal.js +0 -22
  104. package/dist/cockpit/panes/Health.js +0 -30
  105. package/dist/cockpit/panes/Help.js +0 -81
  106. package/dist/cockpit/panes/Output.js +0 -108
  107. package/dist/cockpit/panes/Repos.js +0 -48
  108. package/dist/cockpit/panes/SearchModal.js +0 -31
  109. package/dist/cockpit/state/store.js +0 -111
  110. package/dist/cockpit/tab-state.js +0 -7
  111. package/dist/commands/dev.js +0 -158
  112. package/dist/commands/doctor.js +0 -66
  113. package/dist/commands/init-config-wizard.js +0 -818
  114. package/dist/commands/init-config.js +0 -131
  115. package/dist/commands/mount.js +0 -150
  116. package/dist/core/config.js +0 -152
  117. package/dist/core/logger.js +0 -38
  118. package/dist/core/notifier.js +0 -100
  119. package/dist/core/paths.js +0 -18
  120. package/dist/core/subprocess.js +0 -82
  121. package/dist/core/types.js +0 -1
  122. package/dist/docker/highlights.js +0 -79
  123. package/dist/docker/logs.js +0 -172
  124. package/dist/docker/restart.js +0 -45
  125. package/dist/docker/stack-trace.js +0 -44
  126. package/dist/health/builtin.js +0 -144
  127. package/dist/health/context.js +0 -31
  128. package/dist/health/notify-resolver.js +0 -28
  129. package/dist/health/registry.js +0 -64
  130. package/dist/health/remediations.js +0 -41
  131. package/dist/health/runner.js +0 -22
  132. package/dist/health/scheduler.js +0 -107
  133. package/dist/health/types.js +0 -1
  134. package/dist/health/useHealth.js +0 -122
  135. package/dist/lint/reactive.js +0 -131
  136. package/dist/runCockpit.js +0 -75
  137. package/dist/watchers/manager.js +0 -239
  138. package/dist/watchers/path-mapper.js +0 -29
  139. package/dist/watchers/types.js +0 -9
  140. package/docs/watchers.md +0 -27
package/dist/ink.js CHANGED
@@ -1 +1,38 @@
1
- export { Box, Text, render, useApp, useInput, useFocus, useFocusManager, useStdout, useStderr, useStdin, Static, Newline, Spacer, Transform } from 'ink';
1
+ import { createRequire as __createRequireDC } from 'node:module';
2
+ const require = __createRequireDC(import.meta.url);
3
+
4
+ import {
5
+ Box_default,
6
+ Newline,
7
+ Spacer,
8
+ Static,
9
+ Text,
10
+ Transform,
11
+ render_default,
12
+ use_app_default,
13
+ use_focus_default,
14
+ use_focus_manager_default,
15
+ use_input_default,
16
+ use_stderr_default,
17
+ use_stdin_default,
18
+ use_stdout_default
19
+ } from "./chunk-Q6677JQF.js";
20
+ import "./chunk-VN6UILQW.js";
21
+ import "./chunk-6XGHLLYT.js";
22
+ export {
23
+ Box_default as Box,
24
+ Newline,
25
+ Spacer,
26
+ Static,
27
+ Text,
28
+ Transform,
29
+ render_default as render,
30
+ use_app_default as useApp,
31
+ use_focus_default as useFocus,
32
+ use_focus_manager_default as useFocusManager,
33
+ use_input_default as useInput,
34
+ use_stderr_default as useStderr,
35
+ use_stdin_default as useStdin,
36
+ use_stdout_default as useStdout
37
+ };
38
+ //# sourceMappingURL=ink.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Docker Compose overlay renderer.
3
+ *
4
+ * Generates a valid docker-compose.yml override that bind-mounts each entry's
5
+ * hostPath onto containerPath inside the named service. Hand-rolled (no YAML
6
+ * dependency) so output stays stable + diff-friendly.
7
+ *
8
+ * Uses the explicit `type: bind` long-form with `create_host_path: false` so
9
+ * docker refuses to start if the host directory disappears (early signal vs.
10
+ * silent empty mount — the short-form `host:container` syntax auto-creates).
11
+ */
12
+ import type { MountEntry } from './types.js';
13
+ export interface RenderOverlayOptions {
14
+ service: string;
15
+ /** Optional banner comment at top of the file. */
16
+ banner?: string;
17
+ /** Whether docker may auto-create the host path if missing (default: false). */
18
+ createHostPath?: boolean;
19
+ }
20
+ export declare function renderDockerOverlay(mounts: readonly MountEntry[], opts: RenderOverlayOptions): string;
21
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/mount/compose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,IAAI,EAAE,oBAAoB,GACzB,MAAM,CAoBR"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Generic host-clone discovery.
3
+ *
4
+ * A profile typically has a list of "packages" (composer packages, npm
5
+ * workspaces, python wheels, …) and wants to know which ones have a
6
+ * developer clone sitting somewhere under a parent directory. This helper
7
+ * takes the package list + parentDir + a per-package path resolver and
8
+ * returns the subset that exist on disk as directories.
9
+ *
10
+ * The path resolver lets each package land at an arbitrary subpath
11
+ * convention (e.g. `<parent>/plugins/<name>` vs `<parent>/<name>` vs
12
+ * `<parent>/packages/<name>`).
13
+ */
14
+ export interface FsLike {
15
+ existsSync: (p: string) => boolean;
16
+ statSync: (p: string) => {
17
+ isDirectory(): boolean;
18
+ };
19
+ }
20
+ export interface FindHostClonesOptions<P> {
21
+ /** Packages to check. */
22
+ packages: readonly P[];
23
+ /** Parent directory under which clones might exist. */
24
+ parentDir: string;
25
+ /** Per-package: where the host clone would live. */
26
+ resolveHostPath: (pkg: P, parentDir: string) => string;
27
+ /** Optional fs implementation for tests. */
28
+ fsImpl?: FsLike;
29
+ }
30
+ export interface DiscoveredClone<P> {
31
+ package: P;
32
+ hostPath: string;
33
+ }
34
+ export declare function findHostClones<P>(opts: FindHostClonesOptions<P>): DiscoveredClone<P>[];
35
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/mount/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK;QAAE,WAAW,IAAI,OAAO,CAAA;KAAE,CAAC;CACrD;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,yBAAyB;IACzB,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;IACvB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACvD,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CActF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Git branch + dirty detection for a single host path.
3
+ *
4
+ * Used by `mount status` to enrich each row when the host path is a git
5
+ * checkout. Failures are silent — non-git paths simply yield `null`.
6
+ */
7
+ export interface GitInfo {
8
+ branch: string;
9
+ dirty: boolean;
10
+ }
11
+ export declare function readGitInfo(hostPath: string): Promise<GitInfo | null>;
12
+ //# sourceMappingURL=git-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-status.d.ts","sourceRoot":"","sources":["../../src/mount/git-status.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA0B3E"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Mount manifest read/write.
3
+ *
4
+ * The manifest records the currently-applied mount set so subsequent commands
5
+ * (status, clear) and lifecycle hooks (onMountClear) can see what changed.
6
+ */
7
+ import type { MountManifest } from './types.js';
8
+ export declare const CURRENT_MANIFEST_VERSION = 1;
9
+ export declare class MountManifestError extends Error {
10
+ constructor(filePath: string, reason: string);
11
+ }
12
+ export declare function readMountManifest(manifestPath: string): MountManifest | null;
13
+ export declare function writeMountManifest(manifestPath: string, manifest: MountManifest): void;
14
+ export declare function deleteMountManifest(manifestPath: string): boolean;
15
+ export declare function validateMountManifest(filePath: string, raw: unknown): asserts raw is MountManifest;
16
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/mount/manifest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI7C;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAU5E;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAGtF;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAIjE;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,GAAG,IAAI,aAAa,CA4B9B"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * IDE-facing symlink management.
3
+ *
4
+ * Some mount strategies need a host-side symlink so editor tooling (LSPs,
5
+ * file watchers, debuggers) can follow into the live clone even when the
6
+ * container's bind-mount shadows whatever the package manager originally
7
+ * installed. The strategy is profile-supplied — `MountSymlinkStrategy.linkPath`
8
+ * resolves where the link should live for each entry; null means skip.
9
+ */
10
+ import type { MountEntry, MountSymlinkStrategy } from './types.js';
11
+ export interface SymlinkReport {
12
+ /** Symlinks created or already pointing at the right target (idempotent). */
13
+ created: string[];
14
+ /** A real (non-symlink) directory exists at the link path; left untouched. */
15
+ skipped: string[];
16
+ }
17
+ export declare function applyManagedSymlinks(workspaceRoot: string, mounts: readonly MountEntry[], strategy: MountSymlinkStrategy): SymlinkReport;
18
+ export declare function removeManagedSymlinks(workspaceRoot: string, mounts: readonly MountEntry[], strategy: MountSymlinkStrategy): void;
19
+ export interface BrokenLink {
20
+ linkPath: string;
21
+ intendedTarget: string;
22
+ /**
23
+ * 'broken' — symlink exists but its target does not
24
+ * 'missing' — no symlink (or other entry) at the link path
25
+ */
26
+ reason: 'broken' | 'missing';
27
+ mount: MountEntry;
28
+ }
29
+ export declare function detectBrokenSymlinks(workspaceRoot: string, mounts: readonly MountEntry[], strategy: MountSymlinkStrategy): BrokenLink[];
30
+ //# sourceMappingURL=symlinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symlinks.d.ts","sourceRoot":"","sources":["../../src/mount/symlinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,QAAQ,EAAE,oBAAoB,GAC7B,aAAa,CA4Bf;AAED,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,QAAQ,EAAE,oBAAoB,GAC7B,IAAI,CAWN;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,QAAQ,EAAE,oBAAoB,GAC7B,UAAU,EAAE,CAuBd"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Mount subsystem types.
3
+ *
4
+ * A "mount" describes a host directory bind-mounted into a docker container.
5
+ * Profiles can extend each entry with `meta` for richer status output and
6
+ * lifecycle decisions.
7
+ */
8
+ export interface MountEntry {
9
+ /** Absolute path on the host. */
10
+ hostPath: string;
11
+ /** Absolute path inside the container. */
12
+ containerPath: string;
13
+ /**
14
+ * Optional metadata attached by profiles (e.g. logical name, category,
15
+ * source provenance). dev-cockpit treats this as opaque; profile hooks
16
+ * read it.
17
+ */
18
+ meta?: Record<string, unknown>;
19
+ }
20
+ export interface MountManifest {
21
+ version: 1;
22
+ appName: string;
23
+ workspaceRoot: string;
24
+ service: string;
25
+ overlayPath: string;
26
+ mounts: MountEntry[];
27
+ /** ISO 8601 timestamp of last apply. */
28
+ appliedAt: string;
29
+ }
30
+ export interface MountHookCtx {
31
+ workspaceRoot: string;
32
+ mounts: MountEntry[];
33
+ log: (line: string) => void;
34
+ errLog: (line: string) => void;
35
+ }
36
+ export interface MountClearHookCtx extends MountHookCtx {
37
+ /** The mounts that were active before clear. `mounts` is the empty array. */
38
+ previous: MountEntry[];
39
+ }
40
+ export interface MountStatusInfo {
41
+ /** Git branch of the host clone, if it's a git repo. */
42
+ branch?: string;
43
+ /** Whether the host clone has uncommitted changes. */
44
+ dirty?: boolean;
45
+ /** True if the IDE-facing symlink (if any) is broken/missing. */
46
+ brokenSymlink?: boolean;
47
+ /** Extra columns to render in `mount status` (column header → value). */
48
+ extra?: Record<string, string>;
49
+ }
50
+ export type MountStatusEnricher = (mount: MountEntry, ctx: {
51
+ workspaceRoot: string;
52
+ }) => Promise<MountStatusInfo | null> | MountStatusInfo | null;
53
+ export interface MountSymlinkStrategy {
54
+ /**
55
+ * Resolve where the IDE-facing symlink should live for the given mount.
56
+ * Return null to skip symlink management for this entry.
57
+ */
58
+ linkPath: (mount: MountEntry, workspaceRoot: string) => string | null;
59
+ }
60
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mount/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,6EAA6E;IAC7E,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,mBAAmB,GAAG,CAChC,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,KAC3B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,eAAe,GAAG,IAAI,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACvE"}
package/dist/react.js CHANGED
@@ -1 +1,35 @@
1
- export { useState, useEffect, useMemo, useCallback, useRef, useReducer, useContext, useLayoutEffect, createContext, Fragment, } from 'react';
1
+ import { createRequire as __createRequireDC } from 'node:module';
2
+ const require = __createRequireDC(import.meta.url);
3
+
4
+ import {
5
+ require_react
6
+ } from "./chunk-VN6UILQW.js";
7
+ import {
8
+ __toESM
9
+ } from "./chunk-6XGHLLYT.js";
10
+
11
+ // src/react.ts
12
+ var import_react = __toESM(require_react(), 1);
13
+ var export_Fragment = import_react.Fragment;
14
+ var export_createContext = import_react.createContext;
15
+ var export_useCallback = import_react.useCallback;
16
+ var export_useContext = import_react.useContext;
17
+ var export_useEffect = import_react.useEffect;
18
+ var export_useLayoutEffect = import_react.useLayoutEffect;
19
+ var export_useMemo = import_react.useMemo;
20
+ var export_useReducer = import_react.useReducer;
21
+ var export_useRef = import_react.useRef;
22
+ var export_useState = import_react.useState;
23
+ export {
24
+ export_Fragment as Fragment,
25
+ export_createContext as createContext,
26
+ export_useCallback as useCallback,
27
+ export_useContext as useContext,
28
+ export_useEffect as useEffect,
29
+ export_useLayoutEffect as useLayoutEffect,
30
+ export_useMemo as useMemo,
31
+ export_useReducer as useReducer,
32
+ export_useRef as useRef,
33
+ export_useState as useState
34
+ };
35
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/react.ts"],
4
+ "sourcesContent": ["export {\n useState,\n useEffect,\n useMemo,\n useCallback,\n useRef,\n useReducer,\n useContext,\n useLayoutEffect,\n createContext,\n Fragment,\n} from 'react';\nexport type {\n ReactNode,\n ReactElement,\n FC,\n PropsWithChildren,\n Dispatch,\n SetStateAction,\n MutableRefObject,\n RefObject,\n} from 'react';\n"],
5
+ "mappings": ";;;;;;;;;;;AAAA,mBAWO;",
6
+ "names": []
7
+ }
@@ -16,9 +16,12 @@
16
16
  import { type Instance } from 'ink';
17
17
  import { type CockpitProps } from './cockpit/Cockpit.js';
18
18
  import type { Profile } from './core/types.js';
19
+ import type { ActionConfig } from './actions/types.js';
19
20
  export interface RunCockpitOptions extends CockpitProps {
20
21
  /** Optional profile — used to seed helpConfig (sources + defaultPage). */
21
22
  profile?: Profile;
23
+ /** Action registry surfaced through the `:` palette. Seeded into the store. */
24
+ actions?: ActionConfig[];
22
25
  /** Skip the alternate-screen-buffer dance (e.g. for tests). Default: false. */
23
26
  noAltScreen?: boolean;
24
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runCockpit.d.ts","sourceRoot":"","sources":["../src/runCockpit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,wEAAwE;IACxE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,GAAG,EAAE,QAAQ,CAAC;CACf;AAKD,wBAAgB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,gBAAgB,CAyDzE"}
1
+ {"version":3,"file":"runCockpit.d.ts","sourceRoot":"","sources":["../src/runCockpit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,wEAAwE;IACxE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,GAAG,EAAE,QAAQ,CAAC;CACf;AAKD,wBAAgB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,gBAAgB,CA4DzE"}
package/docs/commands.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # Commands
2
2
 
3
- `dev-cockpit` ships four core commands. A profile contributes its own commands via `setupCli(program)` — these register **first**, so a profile can take over a core command name (the matching core command is then skipped).
3
+ `dev-cockpit` ships five core commands. A profile contributes its own commands via `setupCli(program)` — these register **first**, so a profile can take over a core command name (the matching core command is then skipped).
4
4
 
5
- | Command | What it does |
6
- |---------------|-------------------------------------------------------------------------------|
7
- | `dev` | Boots the three-pane TUI (Repos / Output / Health / Help). |
8
- | `doctor` | Runs every registered health check once and prints a status table. |
9
- | `init-config` | Writes a starter `cockpit.yaml` in the current directory. |
10
- | `mount` | Generates a Docker compose overlay for declared bind mounts. |
5
+ | Command | What it does |
6
+ |-------------------|-------------------------------------------------------------------------------|
7
+ | `dev` | Boots the four-pane TUI (Targets / Output / Health / Help). |
8
+ | `doctor` | Runs every registered health check once and prints a status table. |
9
+ | `init-config` | Writes a `cockpit.yaml` (static template or interactive wizard). |
10
+ | `mount` | Manages a docker-compose bind-mount overlay (apply / status / clear). |
11
+ | `migrate-config` | Rewrites `cockpit.yaml` at the current `CONFIG_VERSION`. |
11
12
 
12
13
  ## `dev`
13
14
 
@@ -15,7 +16,7 @@
15
16
  dev-cockpit dev [-c <path>]
16
17
  ```
17
18
 
18
- Loads `cockpit.yaml`, wires the active profile + config-declared health checks into the cockpit shell, and starts an optional Docker log tailer if the config declares services to tail.
19
+ Loads `cockpit.yaml` (auto-migrating older versions in memory), runs the active profile's `boot` lifecycle hook, wires the action registry (built-ins + profile defaults + dynamic boot-result actions + user config), starts an optional Docker log tailer if `config.docker.services[]` is declared, then renders the cockpit shell.
19
20
 
20
21
  ## `doctor`
21
22
 
@@ -28,25 +29,33 @@ Builds the health registry from `config.health[]` plus `profile.healthChecks`, r
28
29
  ## `init-config`
29
30
 
30
31
  ```
31
- dev-cockpit init-config [--with-docker] [-f|--force]
32
+ dev-cockpit init-config [--with-docker] [-i|--interactive] [-f|--force]
32
33
  ```
33
34
 
34
- Writes a `cockpit.yaml` template at the current directory. `--with-docker` uncomments the docker block. The template is otherwise heavily commented — uncomment the sections you need.
35
+ Writes a `cockpit.yaml` at the current directory.
36
+
37
+ - **Static template** (default): heavily commented; uncomment what you need. `--with-docker` uncomments the docker block.
38
+ - **Interactive wizard** (`-i`): 8 steps with auto-detection from `package.json` / `compose.yaml`. Picks up scripts as actions (test/build/lint/format) or processes (dev/watch). Profile-contributed steps via `Profile.wizardSteps` run between Notifications and the summary; their output lands under `profile.<appName>:`. See [init-config.md](./init-config.md).
35
39
 
36
40
  ## `mount`
37
41
 
38
42
  ```
39
- dev-cockpit mount [-c <path>] [-s|--service <name>]
43
+ dev-cockpit mount [-c <path>] [-s|--service <name>] [-q|--quiet] [-e|--exclude <name>]
40
44
  dev-cockpit mount status [-c <path>]
41
- dev-cockpit mount clear [-c <path>]
45
+ dev-cockpit mount clear [-c <path>]
42
46
  ```
43
47
 
44
- Merges `config.mounts[]` with `profile.mountCandidatesProvider?.()`, then writes:
48
+ Merges `config.mounts[]` with `profile.mountCandidatesProvider?.()` and writes a docker-compose overlay + manifest. Interactive picker by default (when candidates exist); `--quiet` skips the prompt. Full reference: [mount.md](./mount.md).
49
+
50
+ ## `migrate-config`
45
51
 
46
- - `<workspace>/docker-compose.dev-cockpit.yml` — the overlay
47
- - `<state-dir>/mount.manifest.json` what was applied + when
52
+ ```
53
+ dev-cockpit migrate-config [-c <path>] [--dry-run]
54
+ ```
48
55
 
49
- See [mount.md](./mount.md) for the full mount story.
56
+ Reads `cockpit.yaml`, runs migrators from whatever version it declares up to the current `CONFIG_VERSION`, writes the result back with a comment banner. Idempotent on a current-version file. `--dry-run` prints the migrated YAML to stdout instead of writing.
57
+
58
+ The `dev` command auto-applies migrations in memory each boot — `migrate-config` exists to persist the change so the warning stops firing.
50
59
 
51
60
  ## Profile setupCli
52
61
 
@@ -69,3 +78,7 @@ export const myProfile: Profile = {
69
78
  ```
70
79
 
71
80
  The profile is invoked **before** the core commands register. Any name the profile claims (`dev`, `doctor`, etc.) silently skips its core counterpart — no overrides API, no array mutation, just registration order.
81
+
82
+ ## `:` command palette (not a CLI command)
83
+
84
+ Inside the running cockpit, `:` opens a vim-style palette over the action registry. Type to substring-filter, ↑/↓ to navigate, Enter to fire, Esc to cancel. Actions can also be bound to a single keystroke via `key:` and dispatched directly in their scope (e.g., `scope: repos:<id>` actions fire on a keypress when that row is selected). See `actions:` in [config-reference.md](./config-reference.md).
@@ -1,19 +1,123 @@
1
1
  # Config reference
2
2
 
3
- A `cockpit.yaml` lives at the root of your project. The cockpit reads it on startup and seeds the store from it.
3
+ A `cockpit.yaml` lives at the root of your project. The cockpit reads it on startup, auto-migrates older `version:` to the current `CONFIG_VERSION`, and seeds the store from it.
4
4
 
5
5
  ## Top-level keys
6
6
 
7
- - `version` (number, required) schema version. Must match the running build's `CONFIG_VERSION`.
8
- - `appName` (string, required) — used as the state-dir name (`~/.local/state/<appName>/...`) and the OS-notification title prefix.
9
- - `watchers` (array) see watchers.md.
10
- - `repos` (array) items to show in the Repos pane.
11
- - `docker` (object) `composeFile` + `services[]`. Omit the whole block on plain-Node projects.
12
- - `highlights` (array) patterns applied to all log streams.
13
- - `health` (array) see health.md.
14
- - `help` (object) extra docs sources + `defaultPage`.
15
- - `notifications` (object) — see notifications.md.
16
- - `profile` (object) namespace for profile-specific extension keys (e.g. `profile.myapp = { ... }`). Each profile validates its own block via its `configSchemaExt`.
7
+ | Key | Type | Required | Notes |
8
+ |---|---|---|---|
9
+ | `version` | number | yes | Current schema version is `2`. Older versions migrate in memory (with a stderr warning); run `dev-cockpit migrate-config` to persist. |
10
+ | `appName` | string | yes | State-dir name (`$XDG_STATE_HOME/<appName>/<workspace-hash>/`) + OS-notification title prefix. |
11
+ | `processes` | array | no | Long-running commands streamed into the Output pane. See `processes:` below. |
12
+ | `repos` | array | no | Code-side rows in the Targets pane. |
13
+ | `docker` | object | no | `composeFile` + `services[]`. Omit on plain-Node projects. |
14
+ | `highlights` | array | no | Regex patterns applied to all output streams (process + docker). Each can carry an explicit `severity:` (else inferred). |
15
+ | `health` | array | no | Health check declarations — see `health:` below. |
16
+ | `actions` | array | no | Named, optionally key-bound shell commands surfaced via the `:` palette and the Targets pane. |
17
+ | `mount` | object | no | `overlayPath`, `manifestFile` overrides. Defaults: `docker-compose.dev-cockpit.yml`, `mount.manifest.json`. |
18
+ | `mounts` | array | no | Explicit `{hostPath, containerPath, meta?}` entries for `dev-cockpit mount`. |
19
+ | `help` | object | no | Extra `sources[]` + `defaultPage`. |
20
+ | `notifications` | object | no | `enabled`, `onTransitionTo[]`, `exclude[]`. |
21
+ | `defaultPane` | enum | no | `repos` (default) \| `output` \| `health` \| `help`. Falls back to Output when the requested tab is hidden. |
22
+ | `profile` | object | no | Namespace for profile-specific extension keys (`profile.<appName>: { ... }`). Each profile validates its block via its `configSchemaExt` (see [ADR 0005](../adr/0005-strict-profile-namespace.md)). |
23
+
24
+ ## `processes:`
25
+
26
+ ```yaml
27
+ processes:
28
+ - id: vite # required, stable identifier; used as Output source tag and Targets row id
29
+ label: Vite dev # optional, displayed in Targets / Output
30
+ command: npm run dev # shell command; runs via sh -c (cmd /c on Windows)
31
+ cwd: ./apps/web # optional; relative to workspaceRoot
32
+ env: # optional; merged on top of process.env
33
+ DEBUG: '1'
34
+ ```
35
+
36
+ Each process gets:
37
+ - A row in the Targets pane (kind: `process`) with a built-in `[r] Restart <id>` action (kill via SIGTERM, respawn) backed by the tagged-spawn lookup.
38
+ - Output lines tagged by `label` or `id`.
39
+ - Highlight matching against `config.highlights[]` — matched lines use the configured severity (overriding the default `info` for stdout / `warn` for stderr).
40
+
41
+ ## `actions:`
42
+
43
+ ```yaml
44
+ actions:
45
+ - id: test # required, unique
46
+ label: Run tests # required, shown in the `:` palette + Targets action panel
47
+ command: npm test # required for YAML; profiles can supply `invoke:` instead (TS-only)
48
+ cwd: ./api # optional
49
+ scope: global # 'global' | 'repos' | 'repos:<rowId>' (default: 'global')
50
+ key: t # optional single keystroke; fires within scope (in addition to `:`)
51
+ ```
52
+
53
+ Scope semantics:
54
+ - `global` — `:` palette only.
55
+ - `repos` — `:` palette AND fires on any selected Targets row when the keystroke matches.
56
+ - `repos:<id>` — fires only when that specific row is selected.
57
+
58
+ Built-in actions are synthesized automatically:
59
+ - Each docker service: `__builtin:restart-docker:<svc>` with `scope: repos:<svc>`, `key: r`.
60
+ - Each process: `__builtin:restart-process:<id>` with `scope: repos:<id>`, `key: r`.
61
+
62
+ User-declared actions with the same `(scope, key)` shadow the built-in.
63
+
64
+ ## `health:`
65
+
66
+ See [health.md](./health.md). Brief shape:
67
+
68
+ ```yaml
69
+ health:
70
+ - id: app-up
71
+ label: app responsive
72
+ type: http-ok # container-running | port-open | http-ok | file-exists | exec-zero
73
+ url: http://localhost:3000/health # type-specific args
74
+ severity: error # ok | warn | error
75
+ triggers: [startup, fsevent] # optional; defaults to ['startup']
76
+ notify: { onTransitionTo: ['error'] } # optional per-check override
77
+ remediation:
78
+ key: R
79
+ label: restart app
80
+ command: docker compose restart app
81
+ cwd: . # optional
82
+ ```
83
+
84
+ ## `mount:` + `mounts:`
85
+
86
+ ```yaml
87
+ mount: # path overrides
88
+ overlayPath: docker-compose.dev-cockpit.yml # workspace-relative
89
+ manifestFile: mount.manifest.json # basename within stateDir
90
+
91
+ mounts: # explicit candidates
92
+ - hostPath: ./packages/api
93
+ containerPath: /srv/api
94
+ meta: # opaque to dev-cockpit; profile hooks read it
95
+ name: api
96
+ ```
97
+
98
+ Full mount story: [mount.md](./mount.md).
99
+
100
+ ## `notifications:`
101
+
102
+ ```yaml
103
+ notifications:
104
+ enabled: true
105
+ onTransitionTo: [] # restrict to specific destination states; empty = all transitions
106
+ exclude: [] # `NotifiableEvent` strings to suppress
107
+ ```
108
+
109
+ See [notifications.md](./notifications.md).
110
+
111
+ ## `help:`
112
+
113
+ ```yaml
114
+ help:
115
+ sources:
116
+ - ./docs # directory tree of markdown pages
117
+ defaultPage: getting-started
118
+ ```
119
+
120
+ Profiles can contribute their own `helpSources` that layer over the generic docs.
17
121
 
18
122
  ## Example
19
123
 
@@ -1,20 +1,23 @@
1
1
  # Getting started
2
2
 
3
- Run `dev-cockpit dev` from a directory that contains a `cockpit.yaml`. The TUI boots into the **Repos** tab and starts any watchers + health checks declared in your config.
3
+ Run `dev-cockpit dev` from a directory that contains a `cockpit.yaml`. The TUI boots into the **Targets** tab (or whatever `config.defaultPane` points at) and starts any processes + health checks declared in your config.
4
+
5
+ Don't have a `cockpit.yaml` yet? `dev-cockpit init-config -i` walks you through it in eight steps with auto-detection from `package.json` / `compose.yaml`.
4
6
 
5
7
  ## At a glance
6
8
 
7
- - **Cycle tabs** — `←` / `→` (or `Tab` / `Shift-Tab`)
9
+ - **Cycle tabs** — `←` / `→` (or `Tab` / `Shift-Tab`). Empty tabs (Targets with no rows, Health with no checks) auto-hide.
8
10
  - **Quit** — `q`
9
11
  - **Toggle notifications for this session** — `n`
12
+ - **Open the `:` command palette** — `:` (any tab). Type to filter actions, ↑↓ to navigate, Enter to fire.
10
13
 
11
- Every tab fills the full terminal. Modals (filter, search) render in place of the active pane.
14
+ Every tab fills the full terminal. Modals (filter, search, `:` palette) render in place of the active pane.
12
15
 
13
16
  ## What the panes do
14
17
 
15
- - **Repos** — list of repos and (optionally) Docker services with watcher / lint status; per-row actions live here.
16
- - **Output** — streaming logs from watchers and Docker services, with filter and search modals.
17
- - **Health** — workspace health checks; each check has a one-keystroke remediation.
18
+ - **Targets** — repos, docker services, and processes as "runnable units". Split layout (≥200 cols) shows the row list on the left and the actions registered for the selected row on the right; under narrow terminals the panels stack vertically. Built-in `[r]` restarts docker containers and processes; declare more via `config.actions[]` (or a profile's `actions`).
19
+ - **Output** — streaming logs from processes and Docker services. Filter + search modals (`f` / `/`); open the most recent error in `$EDITOR` with `e`. Severity glyphs (`⚠`, `✗`) keep lines scannable without color.
20
+ - **Health** — workspace health checks; each row has a one-keystroke remediation.
18
21
  - **Help** — this guide. `j` / `k` to flip pages, `↑` / `↓` to scroll.
19
22
 
20
23
  ## Try it on a fixture
package/docs/index.md CHANGED
@@ -4,10 +4,14 @@ This is the in-cockpit Help tab. The pages below explain what each pane does, ho
4
4
 
5
5
  - [Getting started](./getting-started.md) — first run and what to expect
6
6
  - [Panes](./panes.md) — Repos, Output, Health, Help
7
- - [Watchers](./watchers.md) — long-running commands streamed into Output
7
+ - [Processes](./processes.md) — long-running commands streamed into Output
8
8
  - [Health](./health.md) — checks and one-keystroke remediations
9
9
  - [Commands](./commands.md) — the four core CLI commands + profile `setupCli`
10
10
  - [init-config](./init-config.md) — scaffold a starter `cockpit.yaml`
11
11
  - [Mount](./mount.md) — host ↔ container bind-mount overlay
12
12
  - [Notifications](./notifications.md) — transition-only OS notifications
13
13
  - [Config reference](./config-reference.md) — `cockpit.yaml` schema
14
+
15
+ ## Accessibility
16
+
17
+ The cockpit honours the [`NO_COLOR`](https://no-color.org) environment variable — set `NO_COLOR=1` (or any non-empty value) and all ANSI colour escapes are stripped. Semantic glyphs (`✓` `⚠` `✗` `●` `○` `▸`) carry the same information in the absence of colour, so panes remain scannable without a terminal palette or for screen-reader users.