dev-cockpit 0.1.0 → 0.2.2

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 (153) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +86 -29
  3. package/bin/dev-cockpit.mjs +26 -4
  4. package/dist/actions/builtin.d.ts +25 -0
  5. package/dist/actions/builtin.d.ts.map +1 -0
  6. package/dist/actions/dispatch.d.ts +21 -0
  7. package/dist/actions/dispatch.d.ts.map +1 -0
  8. package/dist/actions/registry.d.ts +11 -0
  9. package/dist/actions/registry.d.ts.map +1 -0
  10. package/dist/actions/types.d.ts +76 -0
  11. package/dist/actions/types.d.ts.map +1 -0
  12. package/dist/buildCli.d.ts.map +1 -1
  13. package/dist/chunk-6XGHLLYT.js +46 -0
  14. package/dist/chunk-6XGHLLYT.js.map +7 -0
  15. package/dist/chunk-C4GFJDMG.js +79 -0
  16. package/dist/chunk-C4GFJDMG.js.map +7 -0
  17. package/dist/chunk-Q6677JQF.js +32609 -0
  18. package/dist/chunk-Q6677JQF.js.map +7 -0
  19. package/dist/chunk-VN6UILQW.js +1460 -0
  20. package/dist/chunk-VN6UILQW.js.map +7 -0
  21. package/dist/cockpit/Cockpit.d.ts +6 -0
  22. package/dist/cockpit/Cockpit.d.ts.map +1 -1
  23. package/dist/cockpit/Footer.d.ts +6 -4
  24. package/dist/cockpit/Footer.d.ts.map +1 -1
  25. package/dist/cockpit/TabBar.d.ts.map +1 -1
  26. package/dist/cockpit/hooks/useGlobalKeys.d.ts +15 -15
  27. package/dist/cockpit/hooks/useGlobalKeys.d.ts.map +1 -1
  28. package/dist/cockpit/hooks/useTerminalWidth.d.ts +12 -0
  29. package/dist/cockpit/hooks/useTerminalWidth.d.ts.map +1 -0
  30. package/dist/cockpit/panes/CommandModal.d.ts +18 -0
  31. package/dist/cockpit/panes/CommandModal.d.ts.map +1 -0
  32. package/dist/cockpit/panes/Help.d.ts.map +1 -1
  33. package/dist/cockpit/panes/Output.d.ts +7 -0
  34. package/dist/cockpit/panes/Output.d.ts.map +1 -1
  35. package/dist/cockpit/panes/Repos.d.ts.map +1 -1
  36. package/dist/cockpit/state/store.d.ts +14 -11
  37. package/dist/cockpit/state/store.d.ts.map +1 -1
  38. package/dist/cockpit/tab-state.d.ts +12 -0
  39. package/dist/cockpit/tab-state.d.ts.map +1 -1
  40. package/dist/commands/dev.d.ts.map +1 -1
  41. package/dist/commands/doctor.d.ts.map +1 -1
  42. package/dist/commands/init-config-wizard.d.ts +103 -2
  43. package/dist/commands/init-config-wizard.d.ts.map +1 -1
  44. package/dist/commands/init-config.d.ts +2 -0
  45. package/dist/commands/init-config.d.ts.map +1 -1
  46. package/dist/commands/link.d.ts +20 -0
  47. package/dist/commands/link.d.ts.map +1 -0
  48. package/dist/commands/migrate-config.d.ts +18 -0
  49. package/dist/commands/migrate-config.d.ts.map +1 -0
  50. package/dist/commands/mount.d.ts +17 -32
  51. package/dist/commands/mount.d.ts.map +1 -1
  52. package/dist/core/config-discovery.d.ts +39 -0
  53. package/dist/core/config-discovery.d.ts.map +1 -0
  54. package/dist/core/config.d.ts +73 -5
  55. package/dist/core/config.d.ts.map +1 -1
  56. package/dist/core/manifest.d.ts +47 -0
  57. package/dist/core/manifest.d.ts.map +1 -0
  58. package/dist/core/migrations.d.ts +33 -0
  59. package/dist/core/migrations.d.ts.map +1 -0
  60. package/dist/core/subprocess.d.ts +20 -0
  61. package/dist/core/subprocess.d.ts.map +1 -1
  62. package/dist/core/types.d.ts +36 -12
  63. package/dist/core/types.d.ts.map +1 -1
  64. package/dist/devtools-YXMW6JJ6.js +3720 -0
  65. package/dist/devtools-YXMW6JJ6.js.map +7 -0
  66. package/dist/docker/highlights.d.ts +14 -4
  67. package/dist/docker/highlights.d.ts.map +1 -1
  68. package/dist/docker/logs.d.ts +3 -2
  69. package/dist/docker/logs.d.ts.map +1 -1
  70. package/dist/health/builtin.d.ts.map +1 -1
  71. package/dist/index.d.ts +14 -3
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +92944 -53
  74. package/dist/index.js.map +7 -0
  75. package/dist/ink.js +38 -1
  76. package/dist/ink.js.map +7 -0
  77. package/dist/link-HXNII7EU.js +65 -0
  78. package/dist/link-HXNII7EU.js.map +7 -0
  79. package/dist/mount/compose.d.ts +21 -0
  80. package/dist/mount/compose.d.ts.map +1 -0
  81. package/dist/mount/discovery.d.ts +35 -0
  82. package/dist/mount/discovery.d.ts.map +1 -0
  83. package/dist/mount/git-status.d.ts +12 -0
  84. package/dist/mount/git-status.d.ts.map +1 -0
  85. package/dist/mount/manifest.d.ts +16 -0
  86. package/dist/mount/manifest.d.ts.map +1 -0
  87. package/dist/mount/symlinks.d.ts +30 -0
  88. package/dist/mount/symlinks.d.ts.map +1 -0
  89. package/dist/mount/types.d.ts +60 -0
  90. package/dist/mount/types.d.ts.map +1 -0
  91. package/dist/react.js +35 -1
  92. package/dist/react.js.map +7 -0
  93. package/dist/runCockpit.d.ts +3 -0
  94. package/dist/runCockpit.d.ts.map +1 -1
  95. package/docs/commands.md +29 -16
  96. package/docs/config-reference.md +115 -11
  97. package/docs/getting-started.md +9 -6
  98. package/docs/index.md +5 -1
  99. package/docs/init-config.md +34 -8
  100. package/docs/mount.md +198 -25
  101. package/docs/notifications.md +14 -13
  102. package/docs/panes.md +36 -15
  103. package/docs/processes.md +42 -0
  104. package/package.json +93 -90
  105. package/dist/buildCli.js +0 -107
  106. package/dist/cli.js +0 -2
  107. package/dist/cockpit/Cockpit.js +0 -73
  108. package/dist/cockpit/Footer.js +0 -33
  109. package/dist/cockpit/TabBar.js +0 -12
  110. package/dist/cockpit/help/content.js +0 -22
  111. package/dist/cockpit/help/loader.js +0 -118
  112. package/dist/cockpit/help/renderer.js +0 -35
  113. package/dist/cockpit/help/types.js +0 -1
  114. package/dist/cockpit/hooks/useCockpitStore.js +0 -5
  115. package/dist/cockpit/hooks/useGlobalKeys.js +0 -173
  116. package/dist/cockpit/panes/FilterModal.js +0 -22
  117. package/dist/cockpit/panes/Health.js +0 -30
  118. package/dist/cockpit/panes/Help.js +0 -81
  119. package/dist/cockpit/panes/Output.js +0 -108
  120. package/dist/cockpit/panes/Repos.js +0 -48
  121. package/dist/cockpit/panes/SearchModal.js +0 -31
  122. package/dist/cockpit/state/store.js +0 -111
  123. package/dist/cockpit/tab-state.js +0 -7
  124. package/dist/commands/dev.js +0 -158
  125. package/dist/commands/doctor.js +0 -66
  126. package/dist/commands/init-config-wizard.js +0 -818
  127. package/dist/commands/init-config.js +0 -131
  128. package/dist/commands/mount.js +0 -150
  129. package/dist/core/config.js +0 -152
  130. package/dist/core/logger.js +0 -38
  131. package/dist/core/notifier.js +0 -100
  132. package/dist/core/paths.js +0 -18
  133. package/dist/core/subprocess.js +0 -82
  134. package/dist/core/types.js +0 -1
  135. package/dist/docker/highlights.js +0 -79
  136. package/dist/docker/logs.js +0 -172
  137. package/dist/docker/restart.js +0 -45
  138. package/dist/docker/stack-trace.js +0 -44
  139. package/dist/health/builtin.js +0 -144
  140. package/dist/health/context.js +0 -31
  141. package/dist/health/notify-resolver.js +0 -28
  142. package/dist/health/registry.js +0 -64
  143. package/dist/health/remediations.js +0 -41
  144. package/dist/health/runner.js +0 -22
  145. package/dist/health/scheduler.js +0 -107
  146. package/dist/health/types.js +0 -1
  147. package/dist/health/useHealth.js +0 -122
  148. package/dist/lint/reactive.js +0 -131
  149. package/dist/runCockpit.js +0 -75
  150. package/dist/watchers/manager.js +0 -239
  151. package/dist/watchers/path-mapper.js +0 -29
  152. package/dist/watchers/types.js +0 -9
  153. 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,65 @@
1
+ import { createRequire as __createRequireDC } from 'node:module';
2
+ const require = __createRequireDC(import.meta.url);
3
+
4
+ import {
5
+ canonical,
6
+ listMappings,
7
+ manifestPath,
8
+ removeMapping,
9
+ setMapping
10
+ } from "./chunk-C4GFJDMG.js";
11
+ import "./chunk-6XGHLLYT.js";
12
+
13
+ // src/commands/link.ts
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+ function linkAddCommand(opts) {
17
+ const cwd = process.cwd();
18
+ const absConfig = path.resolve(cwd, opts.configPath);
19
+ if (!fs.existsSync(absConfig)) {
20
+ process.stderr.write(
21
+ `dev-cockpit link: ${absConfig} doesn't exist. Create the config file first or pass a valid path.
22
+ `
23
+ );
24
+ process.exit(1);
25
+ }
26
+ setMapping(cwd, absConfig);
27
+ process.stdout.write(
28
+ `dev-cockpit link: ${canonical(cwd)} \u2192 ${canonical(absConfig)}
29
+ `
30
+ );
31
+ }
32
+ function linkListCommand() {
33
+ const entries = listMappings();
34
+ if (entries.length === 0) {
35
+ process.stdout.write(
36
+ `dev-cockpit link: no mappings registered (manifest at ${manifestPath()}).
37
+ `
38
+ );
39
+ return;
40
+ }
41
+ const longest = Math.max(...entries.map((e) => e.workspace.length));
42
+ for (const { workspace, config } of entries) {
43
+ process.stdout.write(`${workspace.padEnd(longest)} \u2192 ${config}
44
+ `);
45
+ }
46
+ }
47
+ function linkRemoveCommand() {
48
+ const cwd = process.cwd();
49
+ const removed = removeMapping(cwd);
50
+ if (removed) {
51
+ process.stdout.write(`dev-cockpit link: removed mapping for ${canonical(cwd)}
52
+ `);
53
+ } else {
54
+ process.stdout.write(
55
+ `dev-cockpit link: no mapping for ${canonical(cwd)} (nothing to remove)
56
+ `
57
+ );
58
+ }
59
+ }
60
+ export {
61
+ linkAddCommand,
62
+ linkListCommand,
63
+ linkRemoveCommand
64
+ };
65
+ //# sourceMappingURL=link-HXNII7EU.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/commands/link.ts"],
4
+ "sourcesContent": ["/**\n * `dev-cockpit link` \u2014 manage the project\u2192config mapping in\n * $XDG_DATA_HOME/dev-cockpit/manifest.json.\n *\n * Sub-commands:\n * link <config-path> register a mapping for the current cwd\n * link list show all registered mappings\n * link remove unregister the current cwd\n *\n * Path canonicalisation (symlink-resolved) happens inside the manifest\n * module \u2014 the same cwd reached via a symlinked alias hashes to the\n * same key as its real path.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n\tcanonical,\n\tlistMappings,\n\tmanifestPath,\n\tremoveMapping,\n\tsetMapping,\n} from '../core/manifest.js';\n\nexport interface LinkAddOptions {\n\tconfigPath: string;\n}\n\nexport function linkAddCommand(opts: LinkAddOptions): void {\n\tconst cwd = process.cwd();\n\tconst absConfig = path.resolve(cwd, opts.configPath);\n\tif (!fs.existsSync(absConfig)) {\n\t\tprocess.stderr.write(\n\t\t\t`dev-cockpit link: ${absConfig} doesn't exist. Create the config file first or pass a valid path.\\n`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\tsetMapping(cwd, absConfig);\n\tprocess.stdout.write(\n\t\t`dev-cockpit link: ${canonical(cwd)} \u2192 ${canonical(absConfig)}\\n`,\n\t);\n}\n\nexport function linkListCommand(): void {\n\tconst entries = listMappings();\n\tif (entries.length === 0) {\n\t\tprocess.stdout.write(\n\t\t\t`dev-cockpit link: no mappings registered (manifest at ${manifestPath()}).\\n`,\n\t\t);\n\t\treturn;\n\t}\n\tconst longest = Math.max(...entries.map((e) => e.workspace.length));\n\tfor (const { workspace, config } of entries) {\n\t\tprocess.stdout.write(`${workspace.padEnd(longest)} \u2192 ${config}\\n`);\n\t}\n}\n\nexport function linkRemoveCommand(): void {\n\tconst cwd = process.cwd();\n\tconst removed = removeMapping(cwd);\n\tif (removed) {\n\t\tprocess.stdout.write(`dev-cockpit link: removed mapping for ${canonical(cwd)}\\n`);\n\t} else {\n\t\tprocess.stdout.write(\n\t\t\t`dev-cockpit link: no mapping for ${canonical(cwd)} (nothing to remove)\\n`,\n\t\t);\n\t}\n}"],
5
+ "mappings": ";;;;;;;;;;;;;AAcA,OAAO,QAAQ;AACf,OAAO,UAAU;AAaV,SAAS,eAAe,MAA4B;AAC1D,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,YAAY,KAAK,QAAQ,KAAK,KAAK,UAAU;AACnD,MAAI,CAAC,GAAG,WAAW,SAAS,GAAG;AAC9B,YAAQ,OAAO;AAAA,MACd,qBAAqB,SAAS;AAAA;AAAA,IAC/B;AACA,YAAQ,KAAK,CAAC;AAAA,EACf;AACA,aAAW,KAAK,SAAS;AACzB,UAAQ,OAAO;AAAA,IACd,qBAAqB,UAAU,GAAG,CAAC,WAAM,UAAU,SAAS,CAAC;AAAA;AAAA,EAC9D;AACD;AAEO,SAAS,kBAAwB;AACvC,QAAM,UAAU,aAAa;AAC7B,MAAI,QAAQ,WAAW,GAAG;AACzB,YAAQ,OAAO;AAAA,MACd,yDAAyD,aAAa,CAAC;AAAA;AAAA,IACxE;AACA;AAAA,EACD;AACA,QAAM,UAAU,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,UAAU,MAAM,CAAC;AAClE,aAAW,EAAE,WAAW,OAAO,KAAK,SAAS;AAC5C,YAAQ,OAAO,MAAM,GAAG,UAAU,OAAO,OAAO,CAAC,aAAQ,MAAM;AAAA,CAAI;AAAA,EACpE;AACD;AAEO,SAAS,oBAA0B;AACzC,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,UAAU,cAAc,GAAG;AACjC,MAAI,SAAS;AACZ,YAAQ,OAAO,MAAM,yCAAyC,UAAU,GAAG,CAAC;AAAA,CAAI;AAAA,EACjF,OAAO;AACN,YAAQ,OAAO;AAAA,MACd,oCAAoC,UAAU,GAAG,CAAC;AAAA;AAAA,IACnD;AAAA,EACD;AACD;",
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