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.
- package/CHANGELOG.md +58 -0
- package/README.md +86 -29
- package/bin/dev-cockpit.mjs +26 -4
- package/dist/actions/builtin.d.ts +25 -0
- package/dist/actions/builtin.d.ts.map +1 -0
- package/dist/actions/dispatch.d.ts +21 -0
- package/dist/actions/dispatch.d.ts.map +1 -0
- package/dist/actions/registry.d.ts +11 -0
- package/dist/actions/registry.d.ts.map +1 -0
- package/dist/actions/types.d.ts +76 -0
- package/dist/actions/types.d.ts.map +1 -0
- package/dist/buildCli.d.ts.map +1 -1
- package/dist/chunk-6XGHLLYT.js +46 -0
- package/dist/chunk-6XGHLLYT.js.map +7 -0
- package/dist/chunk-C4GFJDMG.js +79 -0
- package/dist/chunk-C4GFJDMG.js.map +7 -0
- package/dist/chunk-Q6677JQF.js +32609 -0
- package/dist/chunk-Q6677JQF.js.map +7 -0
- package/dist/chunk-VN6UILQW.js +1460 -0
- package/dist/chunk-VN6UILQW.js.map +7 -0
- package/dist/cockpit/Cockpit.d.ts +6 -0
- package/dist/cockpit/Cockpit.d.ts.map +1 -1
- package/dist/cockpit/Footer.d.ts +6 -4
- package/dist/cockpit/Footer.d.ts.map +1 -1
- package/dist/cockpit/TabBar.d.ts.map +1 -1
- package/dist/cockpit/hooks/useGlobalKeys.d.ts +15 -15
- package/dist/cockpit/hooks/useGlobalKeys.d.ts.map +1 -1
- package/dist/cockpit/hooks/useTerminalWidth.d.ts +12 -0
- package/dist/cockpit/hooks/useTerminalWidth.d.ts.map +1 -0
- package/dist/cockpit/panes/CommandModal.d.ts +18 -0
- package/dist/cockpit/panes/CommandModal.d.ts.map +1 -0
- package/dist/cockpit/panes/Help.d.ts.map +1 -1
- package/dist/cockpit/panes/Output.d.ts +7 -0
- package/dist/cockpit/panes/Output.d.ts.map +1 -1
- package/dist/cockpit/panes/Repos.d.ts.map +1 -1
- package/dist/cockpit/state/store.d.ts +14 -11
- package/dist/cockpit/state/store.d.ts.map +1 -1
- package/dist/cockpit/tab-state.d.ts +12 -0
- package/dist/cockpit/tab-state.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 +103 -2
- package/dist/commands/init-config-wizard.d.ts.map +1 -1
- package/dist/commands/init-config.d.ts +2 -0
- package/dist/commands/init-config.d.ts.map +1 -1
- package/dist/commands/link.d.ts +20 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/migrate-config.d.ts +18 -0
- package/dist/commands/migrate-config.d.ts.map +1 -0
- package/dist/commands/mount.d.ts +17 -32
- package/dist/commands/mount.d.ts.map +1 -1
- package/dist/core/config-discovery.d.ts +39 -0
- package/dist/core/config-discovery.d.ts.map +1 -0
- package/dist/core/config.d.ts +73 -5
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/manifest.d.ts +47 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/migrations.d.ts +33 -0
- package/dist/core/migrations.d.ts.map +1 -0
- package/dist/core/subprocess.d.ts +20 -0
- package/dist/core/subprocess.d.ts.map +1 -1
- package/dist/core/types.d.ts +36 -12
- package/dist/core/types.d.ts.map +1 -1
- package/dist/devtools-YXMW6JJ6.js +3720 -0
- package/dist/devtools-YXMW6JJ6.js.map +7 -0
- package/dist/docker/highlights.d.ts +14 -4
- package/dist/docker/highlights.d.ts.map +1 -1
- package/dist/docker/logs.d.ts +3 -2
- package/dist/docker/logs.d.ts.map +1 -1
- package/dist/health/builtin.d.ts.map +1 -1
- package/dist/index.d.ts +14 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92944 -53
- package/dist/index.js.map +7 -0
- package/dist/ink.js +38 -1
- package/dist/ink.js.map +7 -0
- package/dist/link-HXNII7EU.js +65 -0
- package/dist/link-HXNII7EU.js.map +7 -0
- package/dist/mount/compose.d.ts +21 -0
- package/dist/mount/compose.d.ts.map +1 -0
- package/dist/mount/discovery.d.ts +35 -0
- package/dist/mount/discovery.d.ts.map +1 -0
- package/dist/mount/git-status.d.ts +12 -0
- package/dist/mount/git-status.d.ts.map +1 -0
- package/dist/mount/manifest.d.ts +16 -0
- package/dist/mount/manifest.d.ts.map +1 -0
- package/dist/mount/symlinks.d.ts +30 -0
- package/dist/mount/symlinks.d.ts.map +1 -0
- package/dist/mount/types.d.ts +60 -0
- package/dist/mount/types.d.ts.map +1 -0
- package/dist/react.js +35 -1
- package/dist/react.js.map +7 -0
- package/dist/runCockpit.d.ts +3 -0
- package/dist/runCockpit.d.ts.map +1 -1
- package/docs/commands.md +29 -16
- package/docs/config-reference.md +115 -11
- package/docs/getting-started.md +9 -6
- package/docs/index.md +5 -1
- package/docs/init-config.md +34 -8
- package/docs/mount.md +198 -25
- package/docs/notifications.md +14 -13
- package/docs/panes.md +36 -15
- package/docs/processes.md +42 -0
- package/package.json +93 -90
- package/dist/buildCli.js +0 -107
- package/dist/cli.js +0 -2
- package/dist/cockpit/Cockpit.js +0 -73
- package/dist/cockpit/Footer.js +0 -33
- package/dist/cockpit/TabBar.js +0 -12
- package/dist/cockpit/help/content.js +0 -22
- package/dist/cockpit/help/loader.js +0 -118
- package/dist/cockpit/help/renderer.js +0 -35
- package/dist/cockpit/help/types.js +0 -1
- package/dist/cockpit/hooks/useCockpitStore.js +0 -5
- package/dist/cockpit/hooks/useGlobalKeys.js +0 -173
- package/dist/cockpit/panes/FilterModal.js +0 -22
- package/dist/cockpit/panes/Health.js +0 -30
- package/dist/cockpit/panes/Help.js +0 -81
- package/dist/cockpit/panes/Output.js +0 -108
- package/dist/cockpit/panes/Repos.js +0 -48
- package/dist/cockpit/panes/SearchModal.js +0 -31
- package/dist/cockpit/state/store.js +0 -111
- package/dist/cockpit/tab-state.js +0 -7
- package/dist/commands/dev.js +0 -158
- package/dist/commands/doctor.js +0 -66
- package/dist/commands/init-config-wizard.js +0 -818
- package/dist/commands/init-config.js +0 -131
- package/dist/commands/mount.js +0 -150
- package/dist/core/config.js +0 -152
- package/dist/core/logger.js +0 -38
- package/dist/core/notifier.js +0 -100
- package/dist/core/paths.js +0 -18
- package/dist/core/subprocess.js +0 -82
- package/dist/core/types.js +0 -1
- package/dist/docker/highlights.js +0 -79
- package/dist/docker/logs.js +0 -172
- package/dist/docker/restart.js +0 -45
- package/dist/docker/stack-trace.js +0 -44
- package/dist/health/builtin.js +0 -144
- package/dist/health/context.js +0 -31
- package/dist/health/notify-resolver.js +0 -28
- package/dist/health/registry.js +0 -64
- package/dist/health/remediations.js +0 -41
- package/dist/health/runner.js +0 -22
- package/dist/health/scheduler.js +0 -107
- package/dist/health/types.js +0 -1
- package/dist/health/useHealth.js +0 -122
- package/dist/lint/reactive.js +0 -131
- package/dist/runCockpit.js +0 -75
- package/dist/watchers/manager.js +0 -239
- package/dist/watchers/path-mapper.js +0 -29
- package/dist/watchers/types.js +0 -9
- package/docs/watchers.md +0 -27
package/docs/getting-started.md
CHANGED
|
@@ -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 **
|
|
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
|
-
- **
|
|
16
|
-
- **Output** — streaming logs from
|
|
17
|
-
- **Health** — workspace health checks; each
|
|
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
|
-
- [
|
|
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.
|
package/docs/init-config.md
CHANGED
|
@@ -17,29 +17,55 @@ dev-cockpit init-config -i [-f|--force] # interactive wizard
|
|
|
17
17
|
|
|
18
18
|
## Static template
|
|
19
19
|
|
|
20
|
-
`version:
|
|
20
|
+
`version: 2` and `appName` are required and uncommented. Everything else (processes, repos, docker, highlights, health, actions, help, notifications, mounts) ships as a commented example. Best when you already know what you want — fastest path from scratch to "edit me".
|
|
21
21
|
|
|
22
22
|
## Interactive wizard
|
|
23
23
|
|
|
24
|
-
The recommended path the first time you set the cockpit up on a project.
|
|
24
|
+
The recommended path the first time you set the cockpit up on a project. Eight steps, with project sniffing pre-populating sensible defaults so you usually just press enter:
|
|
25
25
|
|
|
26
26
|
| Step | Section | What it asks + auto-detects |
|
|
27
27
|
|------|---------|------------------------------|
|
|
28
28
|
| 1 | **App name** | Defaults to `package.json` `name`, then the cwd basename. |
|
|
29
29
|
| 2 | **Docker** | Detects `compose.yaml` / `docker-compose.yml` and parses its services. Offers them as a multi-select. Skip entirely for non-compose projects. |
|
|
30
|
-
| 3 | **
|
|
31
|
-
| 4 | **
|
|
32
|
-
| 5 | **Highlights** | Regex patterns that re-colour matching Output lines. `error`-severity matches additionally feed the Recent Errors strip + OS notifications. |
|
|
33
|
-
| 6 | **Health** |
|
|
34
|
-
| 7 | **
|
|
30
|
+
| 3 | **Processes** | Surfaces `package.json` scripts (`dev`, `watch`, `start`, `serve`) as pre-checked candidates. Anything that runs forever and writes to stdout — `vite`, `tsc --watch`, `php artisan serve`, `tail -f storage/logs/laravel.log` — fits here. |
|
|
31
|
+
| 4 | **Targets** | Detects npm/yarn/pnpm workspaces; falls back to a single `.` entry. Each becomes a row in the Targets pane. The way to attach keystrokes to a repo is the Actions step (step 7), with `scope: repos:<id>` + `key:`. |
|
|
32
|
+
| 5 | **Highlights** | Regex patterns that re-colour matching Output lines. `error`-severity matches additionally feed the Recent Errors strip + OS notifications. Patterns now apply to process stdout/stderr too — not just docker logs. |
|
|
33
|
+
| 6 | **Health** | Test-and-fix pairs. Pick one of the five built-in types (`container-running`, `port-open`, `http-ok`, `file-exists`, `exec-zero`), supply the type-specific arg(s), then bind a single-keystroke remediation. Add as many checks as you like — same type repeats freely. `container-running` is hidden when no docker block was declared. |
|
|
34
|
+
| 7 | **Actions** | One-shot shell commands surfaced through the `:` palette and/or bound to a single keypress. Auto-seeds from `package.json` scripts (`test`, `build`, `lint`, `format`, `typecheck`) with sensible default keys (`t`, `b`, `l`, `f`). Custom actions can be added inline. Distinct from processes (long-running) and health (state-checked). |
|
|
35
|
+
| 8 | **Notifications** | Toggle native OS notifications on state transitions. |
|
|
35
36
|
|
|
36
37
|
After writing the file, the wizard offers to run `dev-cockpit doctor` immediately so you get instant feedback that the config parses + each declared health check has a baseline state.
|
|
37
38
|
|
|
38
39
|
The wizard scaffolds a *working* config. Anything more advanced (custom triggers, `expectStatus`, exec args, mounts, profile namespaces) is a hand-edit on the generated file.
|
|
39
40
|
|
|
41
|
+
## Profile-contributed steps
|
|
42
|
+
|
|
43
|
+
Profiles can append their own wizard steps via `Profile.wizardSteps?: WizardStep[]`. Each step runs after step 8 (Notifications) and before the final summary. Step output (YAML lines, returned from `run(ctx)`) lands under `profile.<appName>:` in the generated cockpit.yaml — the namespace defined by [ADR 0005](../adr/0005-strict-profile-namespace.md).
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import type { Profile, WizardStep } from 'dev-cockpit';
|
|
47
|
+
|
|
48
|
+
const gitlabStep: WizardStep = {
|
|
49
|
+
id: 'gitlab-config',
|
|
50
|
+
title: 'GitLab integration',
|
|
51
|
+
description: 'Where does this project live in your gitlab?',
|
|
52
|
+
async run(ctx) {
|
|
53
|
+
const host = await ctx.prompts.input({ message: 'GitLab host', default: 'gitlab.com' });
|
|
54
|
+
return ['gitlab:', ` host: ${host}`];
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const myProfile: Profile = {
|
|
59
|
+
appName: 'myapp',
|
|
60
|
+
wizardSteps: [gitlabStep],
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Step context (`ctx`) exposes the lazy-loaded `prompts` (inquirer subset), `hints` (sniffed project metadata), `workspaceRoot`, and a read-only snapshot of the core-step answers via `result`.
|
|
65
|
+
|
|
40
66
|
## Profile-driven defaults
|
|
41
67
|
|
|
42
|
-
When a profile is active (e.g. `<profile-bin> init-config -i`), the wizard defaults `appName` to the profile's
|
|
68
|
+
When a profile is active (e.g. `<profile-bin> init-config -i`), the wizard defaults `appName` to the profile's `appName`. Profile bundles can also register their own `init-config` via `setupCli(program)` if they want a domain-specific template — the generic command is skipped when the profile claims the slot.
|
|
43
69
|
|
|
44
70
|
## Schema reference
|
|
45
71
|
|
package/docs/mount.md
CHANGED
|
@@ -1,55 +1,228 @@
|
|
|
1
1
|
# Mount
|
|
2
2
|
|
|
3
|
-
`dev-cockpit mount` generates a Docker compose overlay
|
|
3
|
+
`dev-cockpit mount` generates a Docker compose overlay that bind-mounts host directories into container paths, so changes in a local checkout flow live into the running container without rebuilds.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The subsystem is fully generic — it works for any docker-compose project — but profiles can plug in domain logic (package discovery, post-apply restart hooks, IDE-facing symlinks, custom status enrichment) without touching dev-cockpit core.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
# cockpit.yaml
|
|
11
|
+
version: 2
|
|
12
|
+
appName: my-app
|
|
13
|
+
docker:
|
|
14
|
+
composeFile: docker-compose.yml
|
|
15
|
+
services:
|
|
16
|
+
- name: web
|
|
17
|
+
|
|
18
|
+
mounts:
|
|
19
|
+
- hostPath: ./packages/api
|
|
20
|
+
containerPath: /srv/api
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
dev-cockpit mount # interactive picker (or all when --quiet)
|
|
25
|
+
dev-cockpit mount status # active mounts with branch / dirty / broken-symlink
|
|
26
|
+
dev-cockpit mount clear # remove overlay + manifest + symlinks
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Apply the generated overlay alongside your existing compose file:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
docker compose -f docker-compose.yml -f docker-compose.dev-cockpit.yml up -d
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What gets written
|
|
36
|
+
|
|
37
|
+
| File | Default path | Configurable via |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| Compose overlay | `<workspace>/docker-compose.dev-cockpit.yml` | `config.mount.overlayPath` |
|
|
40
|
+
| Manifest | `<stateDir>/mount.manifest.json` | `config.mount.manifestFile` |
|
|
41
|
+
|
|
42
|
+
`<stateDir>` lives under `$XDG_STATE_HOME/<appName>/<workspace-hash>/`. The manifest tracks what was applied and when, and is the source of truth for `status` and `clear`.
|
|
43
|
+
|
|
44
|
+
Override the paths when the wrapper has its own conventions:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
mount:
|
|
48
|
+
overlayPath: docker/compose/web/docker-compose.dev-link.yml
|
|
49
|
+
manifestFile: dev-link.manifest.json
|
|
50
|
+
```
|
|
8
51
|
|
|
9
52
|
## Mount sources
|
|
10
53
|
|
|
11
54
|
Mounts come from two places, merged on `containerPath` (config wins on collision):
|
|
12
55
|
|
|
13
|
-
1. **`config.mounts[]`** — explicit, declared in
|
|
56
|
+
1. **`config.mounts[]`** — explicit, declared in cockpit.yaml:
|
|
14
57
|
```yaml
|
|
15
58
|
mounts:
|
|
16
59
|
- hostPath: ./packages/api
|
|
17
60
|
containerPath: /srv/api
|
|
61
|
+
meta: # optional opaque metadata (read by profile hooks + status)
|
|
62
|
+
name: api
|
|
63
|
+
type: package
|
|
18
64
|
```
|
|
19
|
-
2. **`profile.mountCandidatesProvider?.()`** — discovered programmatically
|
|
65
|
+
2. **`profile.mountCandidatesProvider?.()`** — discovered programmatically (walk a manifest file, scan a parent directory, etc.).
|
|
20
66
|
|
|
21
|
-
|
|
67
|
+
The `meta` field is opaque to dev-cockpit; profile hooks (status enricher, symlink strategy) read it.
|
|
22
68
|
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
docker compose -f docker-compose.yml -f docker-compose.dev-cockpit.yml up -d
|
|
26
|
-
```
|
|
27
|
-
- `<state-dir>/mount.manifest.json` — records what was applied + when. Used by `mount status` and `mount clear`.
|
|
69
|
+
## Subcommands
|
|
28
70
|
|
|
29
|
-
|
|
71
|
+
```
|
|
72
|
+
dev-cockpit mount [options] # write overlay + manifest
|
|
73
|
+
-c, --config <path> # default: ./cockpit.yaml
|
|
74
|
+
-s, --service <name> # default: first in docker.services
|
|
75
|
+
-q, --quiet # skip interactive picker; apply all candidates
|
|
76
|
+
-e, --exclude <name> # exclude a candidate by meta.name (repeatable)
|
|
30
77
|
|
|
31
|
-
|
|
78
|
+
dev-cockpit mount status [options] # branch + dirty + broken-symlink table
|
|
79
|
+
dev-cockpit mount clear [options] # remove overlay + manifest + managed symlinks
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Interactive picker
|
|
83
|
+
|
|
84
|
+
When `mount` runs with discoverable candidates (from `profile.mountCandidatesProvider`) and no `--quiet`, it opens a checkbox picker. Bare-config consumers (only `config.mounts[]`, no provider) bypass the picker — config entries are taken as-is.
|
|
85
|
+
|
|
86
|
+
### Status
|
|
87
|
+
|
|
88
|
+
`mount status` prints a table per active mount with auto-enriched columns:
|
|
32
89
|
|
|
33
90
|
```
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
91
|
+
NAME BRANCH DIRTY
|
|
92
|
+
---- ------ -----
|
|
93
|
+
api feat/redis-cache yes
|
|
94
|
+
worker main no [BROKEN SYMLINK]
|
|
37
95
|
```
|
|
38
96
|
|
|
39
|
-
|
|
97
|
+
- **branch / dirty**: auto-detected via `git -C <hostPath> rev-parse --abbrev-ref HEAD` + `git status --porcelain`. Non-git host paths show `?`.
|
|
98
|
+
- **broken-symlink**: only when the profile supplies a `mountSymlinks` strategy (see below). Otherwise the column is omitted.
|
|
99
|
+
- Extra columns: profile-supplied `mountStatusEnricher` can return arbitrary `extra: { columnName: value }` per row.
|
|
40
100
|
|
|
41
|
-
|
|
101
|
+
### Clear
|
|
42
102
|
|
|
43
|
-
|
|
103
|
+
`mount clear` removes the overlay file, the manifest, and any managed symlinks (if a `mountSymlinks` strategy is defined). Then it calls `profile.onMountClear(ctx)` with the previous mount set — that's where consumers run things like `composer install` or `npm install` to restore whatever the mounts had shadowed.
|
|
104
|
+
|
|
105
|
+
## Profile hooks
|
|
106
|
+
|
|
107
|
+
Profiles plug in via five optional fields on the `Profile` interface:
|
|
44
108
|
|
|
45
109
|
```ts
|
|
110
|
+
import type { Profile } from 'dev-cockpit';
|
|
111
|
+
|
|
46
112
|
export const myProfile: Profile = {
|
|
47
113
|
appName: 'my-app',
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
114
|
+
|
|
115
|
+
/** Discover mount candidates programmatically. */
|
|
116
|
+
mountCandidatesProvider() { ... },
|
|
117
|
+
|
|
118
|
+
/** Run after overlay + manifest are written. Typical: `docker compose restart <svc>`. */
|
|
119
|
+
async onMountApply(ctx) { ... },
|
|
120
|
+
|
|
121
|
+
/** Run after overlay + manifest + symlinks are removed. Typical: restore deps. */
|
|
122
|
+
async onMountClear(ctx) { ... },
|
|
123
|
+
|
|
124
|
+
/** Optional IDE-facing symlinks applied + removed alongside the overlay. */
|
|
125
|
+
mountSymlinks: { linkPath: (mount, workspaceRoot) => '...' },
|
|
126
|
+
|
|
127
|
+
/** Per-row column enrichment for `mount status`. */
|
|
128
|
+
async mountStatusEnricher(mount, ctx) { ... },
|
|
54
129
|
};
|
|
55
130
|
```
|
|
131
|
+
|
|
132
|
+
### `mountCandidatesProvider() → Mount[] | Promise<Mount[]>`
|
|
133
|
+
|
|
134
|
+
Discover candidates from whatever convention the consumer uses (composer.json, package.json workspaces, etc.). Return `Mount[]` with `hostPath` + `containerPath` set; populate `meta` for downstream hooks:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
mountCandidatesProvider() {
|
|
138
|
+
return findLocalCheckouts().map((c) => ({
|
|
139
|
+
hostPath: c.hostPath,
|
|
140
|
+
containerPath: `/srv/${c.name}`,
|
|
141
|
+
meta: { name: c.name, type: c.type },
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `onMountApply(ctx) → Promise<void>`
|
|
147
|
+
|
|
148
|
+
Called after the overlay and manifest are written. Common move: restart the docker service so the new mounts take effect.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
async onMountApply(ctx) {
|
|
152
|
+
await execa('docker', ['compose', 'restart', 'web'], { cwd: ctx.workspaceRoot });
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`ctx` carries `workspaceRoot`, the freshly-applied `mounts[]`, and `log` / `errLog` callbacks that route to the cockpit's Output pane.
|
|
157
|
+
|
|
158
|
+
### `onMountClear(ctx) → Promise<void>`
|
|
159
|
+
|
|
160
|
+
Called after the overlay + manifest + symlinks are removed. `ctx.previous` holds the mount set that was just cleared. Typical: re-install whatever the mounts had shadowed.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
async onMountClear(ctx) {
|
|
164
|
+
if (ctx.previous.length === 0) return;
|
|
165
|
+
await execa('npm', ['install'], { cwd: ctx.workspaceRoot });
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `mountSymlinks: MountSymlinkStrategy`
|
|
170
|
+
|
|
171
|
+
Some package managers expect the on-disk path to exist even when a bind-mount shadows it (composer installer-paths, npm install-from-disk, etc.). The symlink strategy creates host-side symlinks alongside the overlay so IDE tooling (LSPs, file watchers, debuggers) can follow into the live clone:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
mountSymlinks: {
|
|
175
|
+
linkPath(mount, workspaceRoot) {
|
|
176
|
+
const name = mount.meta?.name;
|
|
177
|
+
if (typeof name !== 'string') return null; // skip mounts without metadata
|
|
178
|
+
return path.join(workspaceRoot, 'vendor', name);
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Return `null` for mounts that shouldn't get a symlink. Symlinks are removed by `mount clear`; `mount status` detects broken ones (target moved or deleted) and surfaces them in the table.
|
|
184
|
+
|
|
185
|
+
### `mountStatusEnricher(mount, ctx) → MountStatusInfo`
|
|
186
|
+
|
|
187
|
+
Add custom columns or override the auto-detected `branch` / `dirty` / `brokenSymlink` flags:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
async mountStatusEnricher(mount, { workspaceRoot }) {
|
|
191
|
+
return {
|
|
192
|
+
extra: {
|
|
193
|
+
tests: await runTestsForMount(mount) ? 'pass' : 'fail',
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Manifest schema
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"version": 1,
|
|
204
|
+
"appName": "my-app",
|
|
205
|
+
"workspaceRoot": "/abs/path",
|
|
206
|
+
"service": "web",
|
|
207
|
+
"overlayPath": "/abs/path/docker-compose.dev-cockpit.yml",
|
|
208
|
+
"mounts": [
|
|
209
|
+
{
|
|
210
|
+
"hostPath": "/abs/host/api",
|
|
211
|
+
"containerPath": "/srv/api",
|
|
212
|
+
"meta": { "name": "api", "type": "package" }
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
"appliedAt": "2026-05-11T00:00:00.000Z"
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Re-running `mount` overwrites the manifest with the new applied set. `mount clear` deletes it.
|
|
220
|
+
|
|
221
|
+
## Notes for wrappers upgrading from older manifest filenames
|
|
222
|
+
|
|
223
|
+
If your wrapper previously used a different manifest filename (e.g. a profile that pre-dates the mount lift into dev-cockpit core wrote `dev-link.manifest.json`), the new default is `mount.manifest.json`. Two options:
|
|
224
|
+
|
|
225
|
+
1. **Adopt the new default**: run `mount` once. The new file replaces the legacy one (which is left orphaned in the state dir — safe to delete).
|
|
226
|
+
2. **Keep the legacy filename**: set `config.mount.manifestFile: dev-link.manifest.json` in cockpit.yaml.
|
|
227
|
+
|
|
228
|
+
Same applies to the overlay path — set `config.mount.overlayPath` if your wrapper expects a specific location for its compose stack.
|
package/docs/notifications.md
CHANGED
|
@@ -14,26 +14,27 @@ OS notifications fire on **state transitions only** — never on every check, ne
|
|
|
14
14
|
- recovered
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
2. **Per-item override** — a `notify:` field on any
|
|
17
|
+
2. **Per-item override** — a `notify:` field on any process or health check:
|
|
18
18
|
|
|
19
19
|
```yaml
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
processes:
|
|
21
|
+
- id: lint
|
|
22
|
+
command: npx eslint . --watch
|
|
23
|
+
notify: false # mute this item
|
|
24
|
+
|
|
25
|
+
health:
|
|
26
|
+
- id: api-up
|
|
27
|
+
type: http-ok
|
|
28
|
+
url: http://localhost:3000/health
|
|
29
|
+
notify:
|
|
30
|
+
onTransitionTo: [error] # only on going-down, not on recovery
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
3. **Session toggle** — press `n` in the cockpit to mute *all* notifications for the current session (overrides config). The Health pane shows the current session state at the bottom.
|
|
32
34
|
|
|
33
35
|
## Events
|
|
34
36
|
|
|
35
|
-
- `health-failed` / `health-recovered` — emitted by the health framework
|
|
36
|
-
- `build-failed`
|
|
37
|
-
- Profiles can emit their own event names; they flow through the same pipeline.
|
|
37
|
+
- `health-failed` / `health-recovered` — emitted by the health framework on state transitions.
|
|
38
|
+
- Profiles can emit their own event names (`build-failed`, `db-disconnect`, anything domain-specific) via the exported `emitEvent` helper; they flow through the same `enabled` + `onTransitionTo` + `exclude` policy.
|
|
38
39
|
|
|
39
40
|
The `appName` configured in `cockpit.yaml` is used as the title prefix on every notification (e.g. `my-app — API responds`).
|
package/docs/panes.md
CHANGED
|
@@ -1,28 +1,47 @@
|
|
|
1
1
|
# Panes
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Four panes cycle via `←` / `→` or `Tab` / `Shift-Tab`. Empty panes hide automatically — Targets hides when no rows are seeded, Health hides when no checks are registered.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Targets
|
|
6
|
+
|
|
7
|
+
Two-column layout when the terminal is at least 200 cols wide: row list on the left, actions for the selected row on the right. Narrower terminals stack vertically (list on top, actions below).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌── Targets ──────────────────┬── Actions for `ticker` (process) ────┐
|
|
11
|
+
│ ▸ ○ web [docker] │ [r] Restart ticker (default) │
|
|
12
|
+
│ ○ db [docker] │ [t] Run tests │
|
|
13
|
+
│ ○ ticker [process] │ │
|
|
14
|
+
│ ● api │ │
|
|
15
|
+
└───────────────────────────┴───────────────────────────────────────┘
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Row kinds
|
|
19
|
+
|
|
20
|
+
| Kind | Source | Built-in `r` |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `repo` | `config.repos[]` or `profile.reposProvider()` | none — declare an action |
|
|
23
|
+
| `docker` | `config.docker.services[]` | `docker compose restart <service>` |
|
|
24
|
+
| `process` | `config.processes[]` | kill + respawn (tagged spawn lookup) |
|
|
25
|
+
|
|
26
|
+
### Status glyphs
|
|
6
27
|
|
|
7
28
|
- ● running (green)
|
|
8
|
-
- ○ idle (gray
|
|
29
|
+
- ○ idle (gray)
|
|
9
30
|
- ✗ failing (red)
|
|
10
31
|
|
|
11
|
-
Lint sub-glyph (after the name): ✓ pass · ! fail · (none) unknown.
|
|
12
|
-
|
|
13
|
-
Selected row is marked with a leading `>` and the pane border is highlighted when this pane has focus.
|
|
32
|
+
Lint sub-glyph (after the name): ✓ pass · ! fail · (none) unknown. The leading `▸` marks the selected row; the pane border highlights when this pane has focus.
|
|
14
33
|
|
|
15
|
-
|
|
34
|
+
### Keystrokes
|
|
16
35
|
|
|
17
|
-
-
|
|
18
|
-
- `
|
|
19
|
-
-
|
|
36
|
+
- `↑` / `↓` — move selection
|
|
37
|
+
- `<key>` (any single character) — fire the first matching action for the selected row from the action registry. Match rule: action whose `scope` is `repos:<rowId>` or `repos` AND whose `key` equals the keystroke. Declared actions win over built-ins on (scope, key) collision so you can shadow the default `r`.
|
|
38
|
+
- `:` — open the `:` command palette (any tab; not Targets-specific)
|
|
20
39
|
|
|
21
|
-
|
|
40
|
+
If no action matches, the keystroke is a silent no-op — the right-side panel lists exactly what's bound, including built-ins tagged `(default)`.
|
|
22
41
|
|
|
23
42
|
## Output
|
|
24
43
|
|
|
25
|
-
Streaming source-tagged logs.
|
|
44
|
+
Streaming source-tagged logs. Severity is shown by a leading glyph (`⚠` warn, `✗` error; info has none) so lines remain scannable without color.
|
|
26
45
|
|
|
27
46
|
- `↑` / `↓` — scroll one line
|
|
28
47
|
- `PgUp` / `PgDn` — scroll one page
|
|
@@ -36,10 +55,12 @@ A "Recent errors" strip appears at the top when one or more error lines have bee
|
|
|
36
55
|
|
|
37
56
|
## Health
|
|
38
57
|
|
|
39
|
-
Each row shows: severity glyph, label, remediation key (if any). `Enter` toggles the diagnostic detail for the selected row. Press the remediation letter to fix.
|
|
58
|
+
Each row shows: severity glyph (`✓` ok, `⚠` warn, `✗` error), label, remediation key (if any). `Enter` toggles the diagnostic detail for the selected row. Press the remediation letter (case-insensitive — declared `R` matches both `r` and `R`) to fire the fix.
|
|
40
59
|
|
|
41
|
-
While a remediation runs, a banner appears at the top and the running row shows
|
|
60
|
+
While a remediation runs, a banner appears at the top and the running row shows `(running…)`.
|
|
42
61
|
|
|
43
62
|
## Help
|
|
44
63
|
|
|
45
|
-
|
|
64
|
+
Live-rendered markdown. `j` / `k` (or `Shift-Tab` / `Tab`) cycle pages. `↑` / `↓` scroll. `g` / `G` jump to top / bottom. `←` / `→` always exit Help to the next tab.
|
|
65
|
+
|
|
66
|
+
Under narrow terminals (< 200 cols), the page-title strip hides and the legend collapses to `[j/k] page i/N` to save space.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Processes
|
|
2
|
+
|
|
3
|
+
A process is a long-running command — `tsc --watch`, `vitest --watch`, `npm run dev`, `php artisan serve`, `tail -f some.log` — declared in `cockpit.yaml` under `processes:`. The cockpit spawns each process once at boot and streams its stdout / stderr into the Output pane, tagged by source.
|
|
4
|
+
|
|
5
|
+
Distinct from:
|
|
6
|
+
- **Actions** (one-shot shell commands surfaced via the `:` palette and per-row keys)
|
|
7
|
+
- **Health checks** (state predicates with one-keystroke remediation)
|
|
8
|
+
- **Docker tailing** (`config.docker` — already managed by docker compose)
|
|
9
|
+
|
|
10
|
+
## Config shape
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
processes:
|
|
14
|
+
- id: typecheck # required, unique; used as the Output source tag and Targets row id
|
|
15
|
+
label: tsc --watch # optional; shown in Repos + Output
|
|
16
|
+
command: npx tsc --watch --noEmit # shell command; runs via sh -c (cmd /c on Windows)
|
|
17
|
+
cwd: ./apps/web # optional; relative to workspaceRoot
|
|
18
|
+
env: # optional; merged on top of process.env
|
|
19
|
+
DEBUG: '1'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`command` runs through the shell so pipes, redirects, env-prefixes, and properly-quoted arguments all work as expected.
|
|
23
|
+
|
|
24
|
+
## Built-in restart
|
|
25
|
+
|
|
26
|
+
Every process gets a Targets row of `kind: process` with a built-in action `[r] Restart <id>` (key: `r`, scope: `repos:<id>`). The implementation: SIGTERM the tagged child (via `killSpawnedByTag`), wait for it to exit, then re-spawn it with the same command + cwd + env.
|
|
27
|
+
|
|
28
|
+
You can shadow `r` with a custom action of the same scope + key — declared actions outrank built-ins in the dispatch precedence.
|
|
29
|
+
|
|
30
|
+
## Output + highlights
|
|
31
|
+
|
|
32
|
+
Each line from a process's stdout / stderr gets:
|
|
33
|
+
- The source label (or `id`) as a tag.
|
|
34
|
+
- Default severity: `info` for stdout, `warn` for stderr.
|
|
35
|
+
- Highlight matching against `config.highlights[]`. A matched pattern's `severity:` wins over the default — so a `pattern: 'boom', severity: error` highlight upgrades any line containing "boom" to `error`, which shows as `✗`-prefixed in Output and feeds the Recent Errors strip.
|
|
36
|
+
|
|
37
|
+
## Lifecycle
|
|
38
|
+
|
|
39
|
+
- Spawned on `dev-cockpit dev` boot.
|
|
40
|
+
- Tagged with the process's `id` so the per-row restart action can find the right child.
|
|
41
|
+
- Reaped on cockpit shutdown (`q` or SIGTERM) via `killAllSpawned` — SIGTERM with a 1.5s SIGKILL fallback.
|
|
42
|
+
- No fsevent-driven respawn — the process command itself (`tsc --watch`, etc.) is expected to handle re-runs internally.
|