@doriandev/devcc 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +589 -389
- package/bin/devcc.mjs +50 -23
- package/dist/devcc/agents/agents.d.ts +119 -0
- package/dist/devcc/agents/agents.d.ts.map +1 -0
- package/dist/devcc/agents/agents.js +182 -0
- package/dist/devcc/agents/agents.js.map +1 -0
- package/dist/devcc/app/App.d.ts +23 -0
- package/dist/devcc/app/App.d.ts.map +1 -1
- package/dist/devcc/app/App.js +451 -19
- package/dist/devcc/app/App.js.map +1 -1
- package/dist/devcc/app/controlPlaneCommands.d.ts +14 -0
- package/dist/devcc/app/controlPlaneCommands.d.ts.map +1 -0
- package/dist/devcc/app/controlPlaneCommands.js +204 -0
- package/dist/devcc/app/controlPlaneCommands.js.map +1 -0
- package/dist/devcc/app/keymap.d.ts.map +1 -1
- package/dist/devcc/app/keymap.js +25 -3
- package/dist/devcc/app/keymap.js.map +1 -1
- package/dist/devcc/automation.d.ts +52 -0
- package/dist/devcc/automation.d.ts.map +1 -0
- package/dist/devcc/automation.js +339 -0
- package/dist/devcc/automation.js.map +1 -0
- package/dist/devcc/cli.d.ts.map +1 -1
- package/dist/devcc/cli.js +73 -3
- package/dist/devcc/cli.js.map +1 -1
- package/dist/devcc/components/Sidebar.d.ts.map +1 -1
- package/dist/devcc/components/Sidebar.js +1 -0
- package/dist/devcc/components/Sidebar.js.map +1 -1
- package/dist/devcc/components/primitives.d.ts.map +1 -1
- package/dist/devcc/components/primitives.js +3 -0
- package/dist/devcc/components/primitives.js.map +1 -1
- package/dist/devcc/core/commands.d.ts +33 -0
- package/dist/devcc/core/commands.d.ts.map +1 -1
- package/dist/devcc/core/commands.js.map +1 -1
- package/dist/devcc/core/config.d.ts +71 -3
- package/dist/devcc/core/config.d.ts.map +1 -1
- package/dist/devcc/core/config.js +189 -5
- package/dist/devcc/core/config.js.map +1 -1
- package/dist/devcc/core/state.d.ts +19 -1
- package/dist/devcc/core/state.d.ts.map +1 -1
- package/dist/devcc/core/state.js +6 -0
- package/dist/devcc/core/state.js.map +1 -1
- package/dist/devcc/environment/EnvironmentService.d.ts +58 -0
- package/dist/devcc/environment/EnvironmentService.d.ts.map +1 -0
- package/dist/devcc/environment/EnvironmentService.js +159 -0
- package/dist/devcc/environment/EnvironmentService.js.map +1 -0
- package/dist/devcc/environment/integrations.d.ts +52 -0
- package/dist/devcc/environment/integrations.d.ts.map +1 -0
- package/dist/devcc/environment/integrations.js +94 -0
- package/dist/devcc/environment/integrations.js.map +1 -0
- package/dist/devcc/environment/tools.d.ts +51 -0
- package/dist/devcc/environment/tools.d.ts.map +1 -0
- package/dist/devcc/environment/tools.js +99 -0
- package/dist/devcc/environment/tools.js.map +1 -0
- package/dist/devcc/git/GitService.d.ts +26 -0
- package/dist/devcc/git/GitService.d.ts.map +1 -1
- package/dist/devcc/git/GitService.js +71 -2
- package/dist/devcc/git/GitService.js.map +1 -1
- package/dist/devcc/git/worktrees.d.ts +88 -0
- package/dist/devcc/git/worktrees.d.ts.map +1 -0
- package/dist/devcc/git/worktrees.js +226 -0
- package/dist/devcc/git/worktrees.js.map +1 -0
- package/dist/devcc/index.d.ts +15 -3
- package/dist/devcc/index.d.ts.map +1 -1
- package/dist/devcc/index.js +14 -2
- package/dist/devcc/index.js.map +1 -1
- package/dist/devcc/init/detect.d.ts +55 -0
- package/dist/devcc/init/detect.d.ts.map +1 -0
- package/dist/devcc/init/detect.js +207 -0
- package/dist/devcc/init/detect.js.map +1 -0
- package/dist/devcc/init/prompt.d.ts +25 -0
- package/dist/devcc/init/prompt.d.ts.map +1 -0
- package/dist/devcc/init/prompt.js +156 -0
- package/dist/devcc/init/prompt.js.map +1 -0
- package/dist/devcc/platform/launch.d.ts +30 -0
- package/dist/devcc/platform/launch.d.ts.map +1 -0
- package/dist/devcc/platform/launch.js +93 -0
- package/dist/devcc/platform/launch.js.map +1 -0
- package/dist/devcc/services/ServiceManager.d.ts +10 -2
- package/dist/devcc/services/ServiceManager.d.ts.map +1 -1
- package/dist/devcc/services/ServiceManager.js +18 -4
- package/dist/devcc/services/ServiceManager.js.map +1 -1
- package/dist/devcc/services/node.d.ts +11 -0
- package/dist/devcc/services/node.d.ts.map +1 -1
- package/dist/devcc/services/node.js +20 -18
- package/dist/devcc/services/node.js.map +1 -1
- package/dist/devcc/services/ollama.d.ts +64 -5
- package/dist/devcc/services/ollama.d.ts.map +1 -1
- package/dist/devcc/services/ollama.js +118 -17
- package/dist/devcc/services/ollama.js.map +1 -1
- package/dist/devcc/services/remote.d.ts +90 -0
- package/dist/devcc/services/remote.d.ts.map +1 -0
- package/dist/devcc/services/remote.js +233 -0
- package/dist/devcc/services/remote.js.map +1 -0
- package/dist/devcc/services/types.d.ts +8 -1
- package/dist/devcc/services/types.d.ts.map +1 -1
- package/dist/devcc/services/types.js.map +1 -1
- package/dist/devcc/utils/exec.d.ts +6 -0
- package/dist/devcc/utils/exec.d.ts.map +1 -1
- package/dist/devcc/utils/exec.js +12 -2
- package/dist/devcc/utils/exec.js.map +1 -1
- package/dist/devcc/verify/verify.d.ts +107 -0
- package/dist/devcc/verify/verify.d.ts.map +1 -0
- package/dist/devcc/verify/verify.js +203 -0
- package/dist/devcc/verify/verify.js.map +1 -0
- package/dist/devcc/views/OverviewView.d.ts.map +1 -1
- package/dist/devcc/views/OverviewView.js +58 -2
- package/dist/devcc/views/OverviewView.js.map +1 -1
- package/dist/devcc/views/ServicesView.d.ts +2 -0
- package/dist/devcc/views/ServicesView.d.ts.map +1 -1
- package/dist/devcc/views/ServicesView.js +15 -0
- package/dist/devcc/views/ServicesView.js.map +1 -1
- package/dist/devcc/views/SystemView.d.ts +10 -1
- package/dist/devcc/views/SystemView.d.ts.map +1 -1
- package/dist/devcc/views/SystemView.js +127 -19
- package/dist/devcc/views/SystemView.js.map +1 -1
- package/dist/devcc/views/WorktreesView.d.ts +48 -0
- package/dist/devcc/views/WorktreesView.d.ts.map +1 -0
- package/dist/devcc/views/WorktreesView.js +235 -0
- package/dist/devcc/views/WorktreesView.js.map +1 -0
- package/package.json +1 -1
- package/src/devcc/agents/agents.ts +292 -0
- package/src/devcc/app/App.ts +529 -22
- package/src/devcc/app/controlPlaneCommands.ts +227 -0
- package/src/devcc/app/keymap.ts +25 -3
- package/src/devcc/automation.ts +409 -0
- package/src/devcc/cli.ts +77 -3
- package/src/devcc/components/Sidebar.ts +1 -0
- package/src/devcc/components/primitives.ts +3 -0
- package/src/devcc/core/commands.ts +34 -0
- package/src/devcc/core/config.ts +275 -11
- package/src/devcc/core/state.ts +25 -0
- package/src/devcc/environment/EnvironmentService.ts +215 -0
- package/src/devcc/environment/integrations.ts +133 -0
- package/src/devcc/environment/tools.ts +151 -0
- package/src/devcc/git/GitService.ts +104 -2
- package/src/devcc/git/worktrees.ts +256 -0
- package/src/devcc/index.ts +66 -2
- package/src/devcc/init/detect.ts +268 -0
- package/src/devcc/init/prompt.ts +179 -0
- package/src/devcc/platform/launch.ts +125 -0
- package/src/devcc/services/ServiceManager.ts +15 -3
- package/src/devcc/services/node.ts +17 -14
- package/src/devcc/services/ollama.ts +162 -19
- package/src/devcc/services/remote.ts +306 -0
- package/src/devcc/services/types.ts +9 -1
- package/src/devcc/utils/exec.ts +26 -2
- package/src/devcc/verify/verify.ts +316 -0
- package/src/devcc/views/OverviewView.ts +84 -2
- package/src/devcc/views/ServicesView.ts +17 -0
- package/src/devcc/views/SystemView.ts +144 -22
- package/src/devcc/views/WorktreesView.ts +270 -0
package/README.md
CHANGED
|
@@ -1,50 +1,76 @@
|
|
|
1
1
|
# Dev Command Center
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@doriandev/devcc)
|
|
4
|
+
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
A single keyboard-driven screen that replaces the pile of terminal tabs you keep open while working on a
|
|
7
|
+
project. Built with [OpenTUI](https://opentui.com).
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
`git status`, another for `pnpm test`, another where you `docker ps` or check
|
|
10
|
-
whether Postgres is up, and a fifth for actually typing commands. State ends up
|
|
11
|
-
scattered: you cannot see at a glance whether the dev server is up, whether your
|
|
12
|
-
tree is dirty, or which of those tabs has the error in it.
|
|
9
|
+
## Quick start
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`.devcc.ts`; runs your `package.json` scripts; stages, commits, pulls and
|
|
21
|
-
pushes.
|
|
22
|
-
- **Collects** - everything it launches streams into one log viewer, per source
|
|
23
|
-
or merged and searchable, so the error you are chasing is not in a tab you
|
|
24
|
-
have scrolled away from.
|
|
25
|
-
|
|
26
|
-
### More than a launcher
|
|
27
|
-
|
|
28
|
-
Three things it does that running the commands by hand does not:
|
|
29
|
-
|
|
30
|
-
- **Brings a stack up in order.** `dependsOn` plus a readiness check means `web`
|
|
31
|
-
waits until `api` is genuinely accepting connections, not merely spawned.
|
|
32
|
-
- **Recovers from crashes.** Opt-in automatic restarts with exponential backoff,
|
|
33
|
-
and it gives up rather than thrashing.
|
|
34
|
-
- **Holds several projects open at once.** Each keeps its processes alive in the
|
|
35
|
-
background while you flip between them with `ctrl+o`.
|
|
36
|
-
|
|
37
|
-
### Where the line is
|
|
38
|
-
|
|
39
|
-
It is not a terminal replacement - there is no shell in it, and it will not run
|
|
40
|
-
interactive commands. It is not a deploy tool or a container manager; it observes
|
|
41
|
-
Docker rather than replacing compose. And it deliberately will not touch
|
|
42
|
-
processes it did not start: anything you launched in another tab shows up as
|
|
43
|
-
detected and read-only.
|
|
11
|
+
```bash
|
|
12
|
+
npm i -g @doriandev/devcc # or: pnpm add -g @doriandev/devcc
|
|
13
|
+
cd ~/code/example.com
|
|
14
|
+
devcc init --agent claude # optional: let an agent write .devcc.ts (or: devcc init)
|
|
15
|
+
devcc
|
|
16
|
+
```
|
|
44
17
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
18
|
+
You need [Bun](https://bun.sh) 1.3+ installed (or Node 26.4+, see [Requirements](#requirements)). No
|
|
19
|
+
configuration is needed to get a useful screen. Press `?` inside the app for the manual.
|
|
20
|
+
|
|
21
|
+
In scripts, CI and AI coding agents, `devcc verify` is the project's quality gate: it runs your checks and
|
|
22
|
+
exits 0 only when all of them pass (see [Verification](#verification)).
|
|
23
|
+
|
|
24
|
+
## Contents
|
|
25
|
+
|
|
26
|
+
- [Why devcc](#why-devcc)
|
|
27
|
+
- [At a glance](#at-a-glance)
|
|
28
|
+
- [Requirements](#requirements)
|
|
29
|
+
- [Usage](#usage)
|
|
30
|
+
- [Worktrees and AI agents](#worktrees-and-ai-agents)
|
|
31
|
+
- [Verification](#verification)
|
|
32
|
+
- [Environment](#environment)
|
|
33
|
+
- [Remote machines](#remote-machines)
|
|
34
|
+
- [Configuration](#configuration)
|
|
35
|
+
- [Keyboard shortcuts](#keyboard-shortcuts)
|
|
36
|
+
- [Known limitations](#known-limitations)
|
|
37
|
+
- [Contributing](#contributing)
|
|
38
|
+
|
|
39
|
+
## Why devcc
|
|
40
|
+
|
|
41
|
+
Working on a real project normally means one tab running `next dev`, another for `git status`, another
|
|
42
|
+
for `pnpm test`, another where you `docker ps` or check whether Postgres is up, and a fifth for actually
|
|
43
|
+
typing commands. You cannot see at a glance whether the dev server is up, whether your tree is dirty, or
|
|
44
|
+
which tab has the error in it.
|
|
45
|
+
|
|
46
|
+
devcc puts that in one place:
|
|
47
|
+
|
|
48
|
+
- **Watches** git branch and changes, which services are actually listening (Docker, Postgres, Redis,
|
|
49
|
+
Ollama, a framework dev server), host CPU / memory / disk, and outdated dependencies.
|
|
50
|
+
- **Controls** the dev processes you declare in `.devcc.ts` (start, stop, restart), runs your
|
|
51
|
+
`package.json` scripts, and stages, commits, pulls and pushes.
|
|
52
|
+
- **Collects** everything it launches into one log viewer, per source or merged and searchable.
|
|
53
|
+
|
|
54
|
+
It also does things that running the commands by hand does not:
|
|
55
|
+
|
|
56
|
+
- **Brings a stack up in order.** `dependsOn` plus a readiness check means `web` waits until `api` is
|
|
57
|
+
genuinely accepting connections, not merely spawned.
|
|
58
|
+
- **Recovers from crashes.** Opt-in automatic restarts with exponential backoff, and it gives up rather
|
|
59
|
+
than thrashing.
|
|
60
|
+
- **Holds several projects open at once.** Each keeps its processes alive in the background while you flip
|
|
61
|
+
between them with `ctrl+o`.
|
|
62
|
+
- **Runs AI agents side by side.** Claude Code and Codex, each in its own git worktree, with their output
|
|
63
|
+
in the log viewer.
|
|
64
|
+
- **Gates the work.** `devcc verify` runs the same checks for you, for CI and for an agent, with an exit
|
|
65
|
+
code that means something.
|
|
66
|
+
|
|
67
|
+
**What it is not.** It is not a terminal replacement: there is no shell in it and it will not run
|
|
68
|
+
interactive commands. It is not a deploy tool or a container manager; it observes Docker rather than
|
|
69
|
+
replacing compose. It orchestrates git, mise, direnv, Claude Code, Codex, Tailscale, SSH and Ollama; it
|
|
70
|
+
replaces none of them. It will never touch a process it did not start.
|
|
71
|
+
|
|
72
|
+
It pays off on projects with more than one long-running process, or when you bounce between repositories.
|
|
73
|
+
For a single `next dev` you would barely notice the difference.
|
|
48
74
|
|
|
49
75
|
## At a glance
|
|
50
76
|
|
|
@@ -71,263 +97,273 @@ the difference - the payoff scales with how many moving parts your setup has.
|
|
|
71
97
|
|
|
72
98
|
## Requirements
|
|
73
99
|
|
|
74
|
-
OpenTUI renders through a native Zig core over FFI, so the dashboard needs one
|
|
75
|
-
of:
|
|
100
|
+
OpenTUI renders through a native Zig core over FFI, so the dashboard needs one of:
|
|
76
101
|
|
|
77
102
|
- **Bun 1.3.0 or newer** (recommended), or
|
|
78
103
|
- **Node.js 26.4.0 or newer**, started with `--experimental-ffi`
|
|
79
104
|
|
|
80
|
-
The `devcc` launcher
|
|
81
|
-
|
|
82
|
-
installation, linting, type checking and the unit tests all run on plain Node.
|
|
105
|
+
You do not have to pick. The `devcc` launcher runs on any Node ≥ 20 and re-execs into Bun, or into Node
|
|
106
|
+
with the right flag, automatically. If neither is available it says so and stops.
|
|
83
107
|
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
npm i -g @doriandev/devcc # or: pnpm add -g @doriandev/devcc
|
|
88
|
-
cd ~/code/example.com
|
|
89
|
-
devcc
|
|
90
|
-
```
|
|
108
|
+
## Usage
|
|
91
109
|
|
|
92
|
-
`devcc` runs against the project you are standing in. To point it somewhere else
|
|
93
|
-
without changing directory:
|
|
110
|
+
`devcc` runs against the project you are standing in. To point it somewhere else:
|
|
94
111
|
|
|
95
112
|
```bash
|
|
96
113
|
devcc -C ~/code/example.com
|
|
97
114
|
```
|
|
98
115
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
the
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
| Command | What it does |
|
|
117
|
+
| ------------------------------ | ------------------------------------------------------------- |
|
|
118
|
+
| `devcc` | Open the dashboard |
|
|
119
|
+
| `devcc verify [--json]` | Run the project's verification steps; exit 0 only if all pass |
|
|
120
|
+
| `devcc worktree list [--json]` | List git worktrees |
|
|
121
|
+
| `devcc env [--json]` | Report installed tools, mise runtimes and direnv status |
|
|
122
|
+
| `devcc init` | Write a starter `.devcc.ts` from what devcc detects |
|
|
123
|
+
| `devcc init --agent <id>` | Let Claude Code or Codex inspect the project and set it up |
|
|
124
|
+
| `devcc init --prompt` | Print that setup prompt for any other agent |
|
|
125
|
+
| `devcc config check [--json]` | Validate the config; exit 0 only when it has no issues |
|
|
126
|
+
|
|
127
|
+
| Option | Description |
|
|
128
|
+
| ------------------- | -------------------------------------------------------- |
|
|
129
|
+
| `-C`, `--cwd <dir>` | Project directory (default: nearest project root) |
|
|
130
|
+
| `--json` | One JSON document on stdout, no colour or escape codes |
|
|
131
|
+
| `--force` | `init`: replace an existing `.devcc.ts` with the starter |
|
|
132
|
+
| `-h`, `--help` | Show usage |
|
|
133
|
+
| `-v`, `--version` | Show the version |
|
|
134
|
+
|
|
135
|
+
`verify`, `worktree list`, `env`, `init` and `config check` do not load the dashboard, so they run on any Node ≥ 20 without Bun,
|
|
136
|
+
which is what you want in CI or inside an agent's sandbox.
|
|
111
137
|
|
|
112
138
|
```bash
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
node bin/devcc.mjs -C ~/code/example.com # or against another project
|
|
118
|
-
pnpm build # compile to dist/
|
|
139
|
+
devcc verify # human-readable, failing output shown inline
|
|
140
|
+
devcc verify --json | jq .summary # "4/5 passed, 1 failed (Tests)"
|
|
141
|
+
devcc worktree list --json | jq -r '.worktrees[].path'
|
|
142
|
+
devcc env # what is installed on this machine
|
|
119
143
|
```
|
|
120
144
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Two prerequisites, then nothing else is required to get a useful screen:
|
|
145
|
+
Set `DEVCC_LOG_LEVEL` (`debug` \| `info` \| `warn` \| `error` \| `silent`) to control the internal
|
|
146
|
+
diagnostics log written to `.devcc/devcc.log`.
|
|
124
147
|
|
|
125
|
-
|
|
126
|
-
2. **A runtime with FFI** - Bun ≥ 1.3, or Node ≥ 26.4 run with
|
|
127
|
-
`--experimental-ffi` (see [Requirements](#requirements)). The launcher
|
|
128
|
-
handles this for you if Bun is installed; if neither is available it says so
|
|
129
|
-
and stops.
|
|
148
|
+
## Worktrees and AI agents
|
|
130
149
|
|
|
131
|
-
|
|
150
|
+
Press `w` (or `0`) for the Worktrees view: every git worktree of the repository, and below them the AI
|
|
151
|
+
agents devcc has started. The worktree devcc is running in is marked `●`.
|
|
132
152
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
| Host metrics | Node's `os` and `fs` APIs - CPU, memory, disk, load, uptime |
|
|
144
|
-
| Tool versions | `git`, `docker` and your package manager, read once in the background |
|
|
153
|
+
```
|
|
154
|
+
WORKTREES
|
|
155
|
+
● main ~/code/devcc main
|
|
156
|
+
○ feature/ai-agents ~/code/devcc-feature-ai-agents 1 agent ▸
|
|
157
|
+
○ fix/process-restart ~/code/devcc-fix-process-restart
|
|
158
|
+
|
|
159
|
+
AI AGENTS
|
|
160
|
+
● running Claude Code feature/ai-agents Add retry to the process manager 2m 10s
|
|
161
|
+
○ stopped Codex fix/process-restart Find why restart loses the pid exit 0
|
|
162
|
+
```
|
|
145
163
|
|
|
146
|
-
|
|
147
|
-
and
|
|
164
|
+
**Worktrees.** `n` asks for a branch (created if it does not exist), a base (default: your current branch)
|
|
165
|
+
and a directory (default: `../<repo>-<branch>`), then runs `git worktree add`. `d` removes the selected
|
|
166
|
+
worktree after a confirmation, with plain `git worktree remove`: devcc never passes `--force`, so git
|
|
167
|
+
refuses when there are uncommitted or untracked changes, and devcc shows that refusal. It also refuses
|
|
168
|
+
to remove the main worktree, the one it is running in, or one where an agent is still working. `o` opens a
|
|
169
|
+
worktree as another project in devcc, `t` opens a terminal there, `e` opens your editor.
|
|
148
170
|
|
|
149
|
-
|
|
171
|
+
**AI agents** (optional: needs the `claude` or `codex` CLI). With a worktree selected, `c` launches Claude
|
|
172
|
+
Code and `x` launches Codex. devcc asks for the task and starts the agent with that worktree as its working
|
|
173
|
+
directory. Agents run non-interactively (`claude -p <task>`, `codex exec <task>`) as managed processes:
|
|
174
|
+
their output streams into the Logs view (`enter` on a session), `s` stops one, and quitting devcc stops
|
|
175
|
+
them all. For an interactive session, open a terminal in the worktree with `t` and run the agent there.
|
|
150
176
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
is safe to restart. Nothing is launched or controlled until you declare it in
|
|
154
|
-
`.devcc.ts`:
|
|
177
|
+
devcc passes no permission flags of its own, so each agent runs with its own defaults, and headless Claude
|
|
178
|
+
Code cannot edit files by default. Grant what you are comfortable with in config:
|
|
155
179
|
|
|
156
180
|
```ts
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
{
|
|
161
|
-
id: "web",
|
|
162
|
-
name: "Next.js",
|
|
163
|
-
command: "pnpm",
|
|
164
|
-
args: ["dev"],
|
|
165
|
-
url: "localhost:3000",
|
|
166
|
-
readiness: { port: 3000 }, // "running" means actually serving
|
|
167
|
-
restartOnCrash: true, // comes back after a crash, with backoff
|
|
168
|
-
},
|
|
169
|
-
],
|
|
170
|
-
commands: [
|
|
171
|
-
{
|
|
172
|
-
id: "migrate",
|
|
173
|
-
title: "Run migrations",
|
|
174
|
-
category: "Database",
|
|
175
|
-
command: "pnpm",
|
|
176
|
-
args: ["db:migrate"],
|
|
177
|
-
confirm: true, // asks first: it mutates the database
|
|
178
|
-
},
|
|
179
|
-
],
|
|
181
|
+
agents: {
|
|
182
|
+
claude: { args: ["--permission-mode", "acceptEdits"] },
|
|
183
|
+
codex: { args: ["--sandbox", "workspace-write"] },
|
|
180
184
|
}
|
|
181
185
|
```
|
|
182
186
|
|
|
183
|
-
|
|
184
|
-
`enter` jumps to that process's logs, and quitting stops everything devcc
|
|
185
|
-
started. The declared command appears in the palette (`/`) and asks before it
|
|
186
|
-
runs.
|
|
187
|
+
## Verification
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
ask for, and devcc will never touch a process it did not start - see
|
|
190
|
-
[Configuration](#configuration) for every available field.
|
|
189
|
+
Declare the checks that decide whether the project can ship:
|
|
191
190
|
|
|
192
|
-
|
|
191
|
+
```ts
|
|
192
|
+
// command ids from `commands`, package.json script names, or inline steps
|
|
193
|
+
verify: ["format:check", "lint", "typecheck", "test", "build"],
|
|
194
|
+
```
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
A name is looked up in `commands` first, then in `package.json` scripts, so you rarely need to repeat
|
|
197
|
+
anything. An inline step is `{ id, name?, command, args?, cwd? }`.
|
|
195
198
|
|
|
196
|
-
|
|
199
|
+
```
|
|
200
|
+
$ devcc verify
|
|
201
|
+
devcc verify · ~/code/shop · 3 step(s)
|
|
202
|
+
|
|
203
|
+
→ lint: pnpm run lint
|
|
204
|
+
✓ lint (2.7s)
|
|
205
|
+
→ test: pnpm run test
|
|
206
|
+
✗ test (1.7s · exit 1)
|
|
207
|
+
FAIL tests/cart.test.ts > applies the discount
|
|
208
|
+
AssertionError: expected 90 to be 81
|
|
209
|
+
→ build: pnpm run build
|
|
210
|
+
✓ build (6.0s)
|
|
211
|
+
|
|
212
|
+
✗ 2/3 passed, 1 failed (test) in 10.4s
|
|
213
|
+
```
|
|
197
214
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
| `↑` / `k`, `↓` / `j` | Previous / next item |
|
|
201
|
-
| `←` / `h`, `→` | Previous / next section |
|
|
202
|
-
| `tab`, `shift+tab` | Cycle sections |
|
|
203
|
-
| `1`…`9` | Jump straight to a section |
|
|
204
|
-
| `p`, `g`, `l`, `d` | Processes, Git, Logs, Dependencies |
|
|
205
|
-
| `enter` | Open / activate the selection |
|
|
206
|
-
| `esc` | Close an overlay |
|
|
207
|
-
| `/` | Command palette |
|
|
208
|
-
| `ctrl+p` | Open another project (others keep running) |
|
|
209
|
-
| `ctrl+o` | Cycle through open projects |
|
|
210
|
-
| `?` / `F1` / `ctrl+k` | The in-app manual (also "Open the manual" in the palette) |
|
|
211
|
-
| `shift+R` | Refresh everything |
|
|
212
|
-
| `q` or `ctrl+c` | Quit (stops the processes devcc started) |
|
|
215
|
+
Steps run one at a time, in order, and a failure does not stop the run, so one pass shows every problem.
|
|
216
|
+
Colour is switched off for the steps and escape codes are stripped from captured output.
|
|
213
217
|
|
|
214
|
-
|
|
218
|
+
| Exit code | Meaning |
|
|
219
|
+
| --------- | ------------------------------------------------------------------------- |
|
|
220
|
+
| `0` | Every step passed |
|
|
221
|
+
| `1` | At least one step failed (or was cancelled) |
|
|
222
|
+
| `2` | Nothing was verified: no steps configured, or a step name matches nothing |
|
|
215
223
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
| `s` | Start or stop the selection |
|
|
219
|
-
| `r` | Restart the selection |
|
|
220
|
-
| `i` | Inspect the selection |
|
|
221
|
-
| `enter` | Jump to that process's logs |
|
|
222
|
-
| `d` | `docker compose down` (confirmed) |
|
|
224
|
+
A missing configuration is an error on purpose: a gate that passes because it checked nothing is worse
|
|
225
|
+
than no gate. That makes a line like this safe to put in an agent's instructions:
|
|
223
226
|
|
|
224
|
-
|
|
227
|
+
```text
|
|
228
|
+
Do not finish until `devcc verify` succeeds.
|
|
229
|
+
```
|
|
225
230
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
| `enter` | Run the selected script |
|
|
229
|
-
| `x` | Stop a running script |
|
|
230
|
-
| `f` / `c` | Filter the list / clear the filter |
|
|
231
|
+
In the dashboard, `shift+V` (or "Project: verify" in the palette) runs the same steps as managed tasks:
|
|
232
|
+
progress shows on the Overview, and each step's output has its own log source.
|
|
231
233
|
|
|
232
|
-
|
|
234
|
+
## Environment
|
|
233
235
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
| `s` / `u` | Stage / unstage the selected file |
|
|
237
|
-
| `d` | Discard file changes (confirmed) |
|
|
238
|
-
| `c` | Commit staged changes |
|
|
239
|
-
| `p` / `shift+P` | Pull / push (push is confirmed) |
|
|
240
|
-
| `f` | Fetch |
|
|
241
|
-
| `r` | Refresh status |
|
|
236
|
+
The System view (`8`) starts with the environment, detected in the background when a project opens and
|
|
237
|
+
re-checked with `r`. `devcc env` prints the same report.
|
|
242
238
|
|
|
243
|
-
|
|
239
|
+
- **Tools**: Node, pnpm, npm, Bun, Git, mise, direnv, Docker, Rust/Cargo, Claude Code, Codex, Tailscale and
|
|
240
|
+
Ollama, each with its version, or "not installed". Missing tools are normal. Every probe has a 3-second
|
|
241
|
+
timeout, so a hung executable shows as a warning instead of freezing anything.
|
|
242
|
+
- **mise** (optional). When mise is installed, the runtimes pinned for this project, read from
|
|
243
|
+
`mise ls --current --json`. An untrusted `mise.toml` is reported, never trusted automatically.
|
|
244
|
+
- **direnv** (optional). Whether the project has an `.envrc`, whether it is allowed, and whether devcc
|
|
245
|
+
itself was started with it loaded. "Environment: direnv allow" in the palette runs `direnv allow` after
|
|
246
|
+
a confirmation; devcc never approves an `.envrc` on its own.
|
|
244
247
|
|
|
245
|
-
|
|
246
|
-
| --- | --------------------------------------- |
|
|
247
|
-
| `r` | Check the registry for updates |
|
|
248
|
-
| `u` | Update the selected package (confirmed) |
|
|
248
|
+
Anything that needs attention is summarised in one line on the Overview.
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
## Remote machines
|
|
251
251
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
| `j` / `k` | Scroll |
|
|
255
|
-
| `PgUp` / `PgDn` | Page |
|
|
256
|
-
| `home` / `end` | Jump to start / end |
|
|
257
|
-
| `f` | Toggle follow |
|
|
258
|
-
| `s` | Search - plain text, or a regex if it parses |
|
|
259
|
-
| `x` | Clear the search |
|
|
260
|
-
| `e` | Toggle errors only (stderr) |
|
|
261
|
-
| `a` | Merged stream of every source, colour-keyed |
|
|
262
|
-
| `tab`, `←` / `→` | Change log source |
|
|
263
|
-
| `c` | Clear the current buffer (all, in the merged view) |
|
|
252
|
+
Declare the machines you develop on. `host` can be an alias from `~/.ssh/config`: devcc resolves it with
|
|
253
|
+
`ssh -G`, so your existing SSH settings apply, and it never stores users, keys or addresses of its own.
|
|
264
254
|
|
|
265
|
-
|
|
255
|
+
```ts
|
|
256
|
+
remoteMachines: [
|
|
257
|
+
{ id: "gpu", name: "GPU Server", host: "gpu-server", transport: "ssh", services: ["gpu-ollama"] },
|
|
258
|
+
],
|
|
259
|
+
```
|
|
266
260
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
261
|
+
Each machine appears under REMOTE in the Services view: whether its SSH port answers and how quickly,
|
|
262
|
+
whether it is online in your tailnet, and the status of its associated services. `o` on a machine opens an
|
|
263
|
+
SSH session in a terminal. Reachability is a TCP connection to the SSH port, made at most once a minute
|
|
264
|
+
while the project is open, plus whenever you refresh.
|
|
271
265
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
are transpiled on the fly, so no build step is needed.
|
|
266
|
+
**Tailscale** (optional). When the `tailscale` CLI is available (including the macOS app's bundled one),
|
|
267
|
+
devcc reads `tailscale status --json` every 30 seconds: connected or not, this node's name, and which of
|
|
268
|
+
your remote machines are online.
|
|
276
269
|
|
|
277
|
-
|
|
270
|
+
**Remote Ollama** (optional). Point a service entry at any Ollama server, whether on localhost, a LAN
|
|
271
|
+
hostname or a Tailscale name:
|
|
278
272
|
|
|
279
273
|
```ts
|
|
280
|
-
|
|
274
|
+
services: [{ id: "gpu-ollama", type: "ollama", baseUrl: "http://gpu-server:11434" }],
|
|
275
|
+
```
|
|
281
276
|
|
|
282
|
-
|
|
283
|
-
|
|
277
|
+
The entry lists the server's models with parameter size, quantisation and disk size, marks the ones
|
|
278
|
+
currently loaded (with VRAM use) from `/api/ps`, and says "unreachable" when the server is down. Remote
|
|
279
|
+
endpoints are checked at most once a minute. The local Ollama on port 11434 (or `OLLAMA_HOST`) is still
|
|
280
|
+
detected automatically.
|
|
284
281
|
|
|
282
|
+
## Configuration
|
|
283
|
+
|
|
284
|
+
### Setting up a project
|
|
285
|
+
|
|
286
|
+
devcc works without a config file, but a good `.devcc.ts` is what makes processes, verification and the
|
|
287
|
+
palette useful. There are three ways to get one:
|
|
288
|
+
|
|
289
|
+
- **`devcc init`** writes a starter from what it can read without running anything: the package manager,
|
|
290
|
+
a `dev` script and its framework's port, and verify steps from existing scripts (format check, lint,
|
|
291
|
+
typecheck, tests, build). Scripts that watch, write files or are npm's placeholder are left out. Rust
|
|
292
|
+
and Go projects get their toolchain's standard checks.
|
|
293
|
+
- **`devcc init --agent claude`** (or `codex`) opens that agent in your terminal with a setup prompt
|
|
294
|
+
built for this project: what devcc detected, the starter as a draft, the full config reference, and
|
|
295
|
+
firm rules (never invent commands or ports, never add secrets or hostnames, keep verify
|
|
296
|
+
non-interactive, confirm anything destructive). The agent reads the README, CI workflows and framework
|
|
297
|
+
configs, writes `.devcc.ts`, and runs `devcc config check` until it is clean. You watch and approve its
|
|
298
|
+
edits as usual. `devcc init --prompt` prints the same prompt for any other agent.
|
|
299
|
+
- **In the dashboard**, a project without config shows a hint. The palette offers "Project: set up
|
|
300
|
+
.devcc.ts from detected scripts", and "Project: set up .devcc.ts with Claude Code / Codex" (also for
|
|
301
|
+
improving an existing config). The dashboard's agent runs headless and cannot edit files, so it prints
|
|
302
|
+
its proposal; devcc validates it, saves it to `.devcc/proposed.devcc.ts` for review, and writes it
|
|
303
|
+
only after you confirm. The project then reloads with the new config.
|
|
304
|
+
|
|
305
|
+
Nothing is set up automatically, and an existing config is never replaced without `--force` or a
|
|
306
|
+
confirmation.
|
|
307
|
+
|
|
308
|
+
### Without a config file
|
|
309
|
+
|
|
310
|
+
Run `devcc` in a project with no configuration and it detects all of this, so Overview, Scripts, Git,
|
|
311
|
+
Services and System are populated on first launch:
|
|
312
|
+
|
|
313
|
+
| Detects | How |
|
|
314
|
+
| --------------- | -------------------------------------------------------------------------------------------- |
|
|
315
|
+
| Project root | Walks up from the working directory looking for `package.json` or `.git` |
|
|
316
|
+
| Package manager | `packageManager` field → lockfile → the manager that launched it → npm |
|
|
317
|
+
| Scripts | `scripts` in `package.json` |
|
|
318
|
+
| Git state | `git status --porcelain=v2`: branch, staged/modified/untracked, ahead/behind, recent commits |
|
|
319
|
+
| Local services | TCP probes for Postgres, Redis and Ollama; the Docker daemon and any compose file |
|
|
320
|
+
| Dev servers | Ports inferred from your dependencies (`next` → 3000, `vite` → 5173, `typesense` → 8108) |
|
|
321
|
+
| Host metrics | Node's `os` and `fs` APIs: CPU, memory, disk, load, uptime |
|
|
322
|
+
| Tool versions | `git`, `docker` and your package manager, read once in the background |
|
|
323
|
+
|
|
324
|
+
### Adding processes and commands
|
|
325
|
+
|
|
326
|
+
devcc cannot guess that `pnpm dev` is the thing you want it to own, that it should wait for port 3000
|
|
327
|
+
before calling it ready, or that it is safe to restart. Nothing is launched or controlled until you declare
|
|
328
|
+
it in `.devcc.ts` in the project root:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
// ~/code/example.com/.devcc.ts
|
|
332
|
+
export default {
|
|
285
333
|
processes: [
|
|
286
334
|
{
|
|
287
|
-
id: "
|
|
288
|
-
name: "
|
|
289
|
-
command: "pnpm",
|
|
290
|
-
args: ["exec", "tsc", "-p", "tsconfig.json", "--noEmit", "--watch", "--pretty", "false"],
|
|
291
|
-
kind: "service",
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
id: "vitest",
|
|
295
|
-
name: "vitest --watch",
|
|
335
|
+
id: "web",
|
|
336
|
+
name: "Next.js",
|
|
296
337
|
command: "pnpm",
|
|
297
|
-
args: ["
|
|
298
|
-
|
|
338
|
+
args: ["dev"],
|
|
339
|
+
url: "localhost:3000",
|
|
340
|
+
readiness: { port: 3000 }, // "running" means actually serving
|
|
341
|
+
restartOnCrash: true, // comes back after a crash, with backoff
|
|
299
342
|
},
|
|
300
343
|
],
|
|
301
|
-
|
|
302
344
|
commands: [
|
|
303
345
|
{
|
|
304
|
-
id: "
|
|
305
|
-
title: "
|
|
306
|
-
category: "
|
|
346
|
+
id: "migrate",
|
|
347
|
+
title: "Run migrations",
|
|
348
|
+
category: "Database",
|
|
307
349
|
command: "pnpm",
|
|
308
|
-
args: ["
|
|
309
|
-
|
|
310
|
-
},
|
|
311
|
-
{
|
|
312
|
-
id: "clean",
|
|
313
|
-
title: "Remove dist/",
|
|
314
|
-
category: "Project",
|
|
315
|
-
command: "rm",
|
|
316
|
-
args: ["-rf", "dist"],
|
|
317
|
-
confirm: true,
|
|
350
|
+
args: ["db:migrate"],
|
|
351
|
+
confirm: true, // asks first: it mutates the database
|
|
318
352
|
},
|
|
319
353
|
],
|
|
320
|
-
|
|
321
|
-
refresh: { system: 1_500, services: 5_000, git: 8_000 },
|
|
322
|
-
})
|
|
354
|
+
}
|
|
323
355
|
```
|
|
324
356
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
357
|
+
Restart devcc and the Processes pane is live: `s` starts or stops, `r` restarts, `enter` jumps to that
|
|
358
|
+
process's logs, and quitting stops everything devcc started. The declared command appears in the palette
|
|
359
|
+
(`/`) and asks before it runs.
|
|
360
|
+
|
|
361
|
+
**Type-checked config.** If the project has `@doriandev/devcc` installed as a dependency, wrap the config
|
|
362
|
+
in `defineConfig` for editor autocompletion. The shape is the same and it is validated either way. A
|
|
363
|
+
monorepo example:
|
|
328
364
|
|
|
329
365
|
```ts
|
|
330
|
-
import { defineConfig } from "
|
|
366
|
+
import { defineConfig } from "@doriandev/devcc"
|
|
331
367
|
|
|
332
368
|
export default defineConfig({
|
|
333
369
|
processes: [
|
|
@@ -362,44 +398,43 @@ export default defineConfig({
|
|
|
362
398
|
})
|
|
363
399
|
```
|
|
364
400
|
|
|
365
|
-
|
|
401
|
+
**File names.** devcc uses the first of `.devcc.ts`, `devcc.config.ts`, `.devcc.mts`, `devcc.config.mts`,
|
|
402
|
+
`.devcc.js`, `devcc.config.js`, `.devcc.mjs`, `devcc.config.mjs` or `.devcc.json` in the project root.
|
|
403
|
+
TypeScript is transpiled on the fly, so no build step is needed.
|
|
366
404
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
export default {
|
|
370
|
-
processes: [{ id: "web", name: "Web", command: "pnpm", args: ["dev"], port: 3000 }],
|
|
371
|
-
}
|
|
372
|
-
```
|
|
405
|
+
**Mistakes are safe.** Invalid entries are reported in **Settings → Config issues** and skipped; a typo
|
|
406
|
+
never stops the dashboard from starting.
|
|
373
407
|
|
|
374
|
-
### Process
|
|
408
|
+
### Process fields
|
|
375
409
|
|
|
376
410
|
| Field | Type | Description |
|
|
377
411
|
| ------------------- | ----------------------- | ------------------------------------------------------------------- |
|
|
378
|
-
| `id` | `string` | Unique id
|
|
379
|
-
| `
|
|
380
|
-
| `command` | `string` | Executable. **Required** - never a shell string |
|
|
412
|
+
| `id` | `string` | **Required.** Unique id, also used as the log source id |
|
|
413
|
+
| `command` | `string` | **Required.** Executable, never a shell string |
|
|
381
414
|
| `args` | `string[]` | Arguments passed as an array, so quoting is never an issue |
|
|
415
|
+
| `name` | `string` | Display name (defaults to `id`) |
|
|
382
416
|
| `cwd` | `string` | Absolute, or relative to the project root |
|
|
383
417
|
| `env` | `Record<string,string>` | Extra environment variables |
|
|
384
418
|
| `kind` | `"service" \| "task"` | Long-running vs. expected to exit (default `service`) |
|
|
385
419
|
| `autoStart` | `boolean` | Start with the dashboard (default `false`) |
|
|
386
420
|
| `url` | `string` | Informational address shown next to the process |
|
|
387
421
|
| `port` | `number` | Port to associate with the process |
|
|
422
|
+
| `dependsOn` | `string[]` | Ids that must be _ready_ before this one starts |
|
|
423
|
+
| `readiness` | `object` | How devcc decides the process is usable, see below |
|
|
388
424
|
| `killGraceMs` | `number` | SIGTERM → SIGKILL grace period (default 5000) |
|
|
389
425
|
| `restartOnCrash` | `boolean` | Bring it back automatically after a non-zero exit (default `false`) |
|
|
390
426
|
| `maxCrashRestarts` | `number` | Give up after this many consecutive crashes (default 5) |
|
|
391
427
|
| `crashBackoffMs` | `number` | First backoff delay, doubling per crash (default 1000) |
|
|
392
428
|
| `maxCrashBackoffMs` | `number` | Backoff ceiling (default 30000) |
|
|
393
429
|
| `healthyAfterMs` | `number` | A run lasting this long resets the crash budget (default 30000) |
|
|
394
|
-
|
|
395
|
-
|
|
430
|
+
|
|
431
|
+
A manual stop cancels any pending crash restart and resets the budget.
|
|
396
432
|
|
|
397
433
|
### Readiness checks
|
|
398
434
|
|
|
399
|
-
Without a readiness block a process is `running` the moment it has spawned.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
layer is actually usable.
|
|
435
|
+
Without a readiness block a process is `running` the moment it has spawned. With one, it stays `starting`
|
|
436
|
+
until the check passes, and `dependsOn` waits for that. So "start all" brings a stack up in the right
|
|
437
|
+
order, and only once each layer is actually usable.
|
|
403
438
|
|
|
404
439
|
```ts
|
|
405
440
|
{
|
|
@@ -423,25 +458,86 @@ layer is actually usable.
|
|
|
423
458
|
| `timeoutMs` | Give up waiting and report `running` anyway, with a warning (default 30000) |
|
|
424
459
|
| `intervalMs` | Port probe interval (default 250) |
|
|
425
460
|
|
|
426
|
-
Either `port` or `logPattern` is required; both may be given. A dependency
|
|
427
|
-
|
|
428
|
-
|
|
461
|
+
Either `port` or `logPattern` is required; both may be given. A dependency cycle is reported and those
|
|
462
|
+
processes are left alone rather than started in an arbitrary order.
|
|
463
|
+
|
|
464
|
+
### Command fields
|
|
465
|
+
|
|
466
|
+
| Field | Type | Description |
|
|
467
|
+
| ------------------------ | ------------------------------- | ------------------------------------------- |
|
|
468
|
+
| `id` | `string` | **Required.** Unique id |
|
|
469
|
+
| `command`, `args`, `cwd` | | As for processes. **`command` is required** |
|
|
470
|
+
| `title` | `string` | Palette entry text |
|
|
471
|
+
| `category` | `string` | Palette grouping (default `Project`) |
|
|
472
|
+
| `keywords` | `string[]` | Extra fuzzy-search terms |
|
|
473
|
+
| `confirm` | `boolean \| { title, message }` | Ask before running |
|
|
474
|
+
|
|
475
|
+
### Service fields
|
|
476
|
+
|
|
477
|
+
Extra ports to watch: `{ id, name, port, host?, healthPath?, category? }`. `healthPath` upgrades the check
|
|
478
|
+
from a TCP probe to an HTTP request. An Ollama server is `{ id, name?, type: "ollama", baseUrl }`; see
|
|
479
|
+
[Remote machines](#remote-machines).
|
|
429
480
|
|
|
430
|
-
###
|
|
481
|
+
### Control-plane fields
|
|
431
482
|
|
|
432
|
-
|
|
433
|
-
| ------------------------ | ------------------------------- | ---------------------------------------- |
|
|
434
|
-
| `id` | `string` | Unique id. **Required** |
|
|
435
|
-
| `title` | `string` | Palette entry text |
|
|
436
|
-
| `category` | `string` | Palette grouping (default `Project`) |
|
|
437
|
-
| `command`, `args`, `cwd` | | As for processes. **`command` required** |
|
|
438
|
-
| `keywords` | `string[]` | Extra fuzzy-search terms |
|
|
439
|
-
| `confirm` | `boolean \| { title, message }` | Ask before running |
|
|
483
|
+
All optional. Nothing here is required for devcc to work.
|
|
440
484
|
|
|
441
|
-
|
|
485
|
+
| Field | Description |
|
|
486
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
487
|
+
| `verify` | Steps for `devcc verify`: command ids, script names, or `{ id, name?, command, args?, cwd? }` |
|
|
488
|
+
| `agents` | Per agent id: `{ command?, args?, name?, enabled? }`. `claude` and `codex` are built in; any other key adds an agent whose task is the last argument |
|
|
489
|
+
| `worktrees.directory` | Where new worktrees go, relative to the main worktree (default `..`) |
|
|
490
|
+
| `editor` | `{ command: "zed" }` (also `code`, `cursor`, `webstorm`, with optional `args`) or, on macOS, `{ application: "WebStorm" }` |
|
|
491
|
+
| `terminal` | macOS default: Terminal. `{ application: "iTerm" }`, or `{ command, args, execArgs }` where `{path}` in `args` is the directory and `execArgs` makes it run a program (used for SSH) |
|
|
492
|
+
| `remoteMachines` | `{ id, name?, host, transport: "ssh", port?, user?, services? }` |
|
|
493
|
+
|
|
494
|
+
### A full example
|
|
495
|
+
|
|
496
|
+
A Next.js app on pnpm, with Claude Code and Codex working in worktrees, models served from a GPU box, and a
|
|
497
|
+
verification gate:
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
// ~/code/shop/.devcc.ts
|
|
501
|
+
import { defineConfig } from "@doriandev/devcc"
|
|
502
|
+
|
|
503
|
+
export default defineConfig({
|
|
504
|
+
name: "shop",
|
|
505
|
+
editor: { command: "zed" },
|
|
506
|
+
|
|
507
|
+
processes: [
|
|
508
|
+
{
|
|
509
|
+
id: "web",
|
|
510
|
+
name: "Next.js",
|
|
511
|
+
command: "pnpm",
|
|
512
|
+
args: ["dev"],
|
|
513
|
+
url: "localhost:3000",
|
|
514
|
+
readiness: { port: 3000 },
|
|
515
|
+
restartOnCrash: true,
|
|
516
|
+
},
|
|
517
|
+
],
|
|
518
|
+
|
|
519
|
+
agents: {
|
|
520
|
+
claude: { args: ["--permission-mode", "acceptEdits"] },
|
|
521
|
+
codex: { args: ["--sandbox", "workspace-write"] },
|
|
522
|
+
},
|
|
523
|
+
worktrees: { directory: "../shop-worktrees" },
|
|
524
|
+
|
|
525
|
+
verify: [
|
|
526
|
+
"lint",
|
|
527
|
+
"typecheck",
|
|
528
|
+
"test",
|
|
529
|
+
{ id: "build", name: "Next.js build", command: "pnpm", args: ["build"] },
|
|
530
|
+
],
|
|
531
|
+
|
|
532
|
+
services: [{ id: "gpu-ollama", type: "ollama", baseUrl: "http://gpu-server:11434" }],
|
|
533
|
+
remoteMachines: [
|
|
534
|
+
{ id: "gpu", name: "RTX 3090 Server", host: "gpu-server", transport: "ssh", services: ["gpu-ollama"] },
|
|
535
|
+
],
|
|
536
|
+
})
|
|
537
|
+
```
|
|
442
538
|
|
|
443
|
-
|
|
444
|
-
`
|
|
539
|
+
Open it with `devcc`, press `w`, then `n` to create `feature/checkout` and `c` to give Claude a task in it.
|
|
540
|
+
Press `shift+V` before you merge; the agent can run `devcc verify` itself.
|
|
445
541
|
|
|
446
542
|
### Other options
|
|
447
543
|
|
|
@@ -454,19 +550,167 @@ Extra ports to watch: `{ id, name, port, host?, healthPath?, category? }`.
|
|
|
454
550
|
| `projects` | Extra project paths offered in the switcher (absolute or relative) |
|
|
455
551
|
| `projectSearchDirs` | Extra directories to scan for sibling projects |
|
|
456
552
|
|
|
457
|
-
|
|
458
|
-
|
|
553
|
+
## Keyboard shortcuts
|
|
554
|
+
|
|
555
|
+
You do not need to memorise these: press `?`, `F1` or `ctrl+k` in the app for the manual, or `/` to search
|
|
556
|
+
every action in the command palette. The footer shows key hints for the current view.
|
|
557
|
+
|
|
558
|
+
### Global
|
|
559
|
+
|
|
560
|
+
| Key | Action |
|
|
561
|
+
| ----------------------- | --------------------------------------------- |
|
|
562
|
+
| `↑` / `k`, `↓` / `j` | Previous / next item |
|
|
563
|
+
| `←` / `h`, `→` | Previous / next section |
|
|
564
|
+
| `tab`, `shift+tab` | Cycle sections |
|
|
565
|
+
| `1`…`9`, `0` | Jump straight to a section (`0` is Worktrees) |
|
|
566
|
+
| `p`, `g`, `w`, `l`, `d` | Processes, Git, Worktrees, Logs, Dependencies |
|
|
567
|
+
| `enter` | Open / activate the selection |
|
|
568
|
+
| `esc` | Close an overlay |
|
|
569
|
+
| `/` | Command palette |
|
|
570
|
+
| `ctrl+p` | Open another project (others keep running) |
|
|
571
|
+
| `ctrl+o` | Cycle through open projects |
|
|
572
|
+
| `?` / `F1` / `ctrl+k` | The in-app manual |
|
|
573
|
+
| `shift+R` | Refresh everything |
|
|
574
|
+
| `shift+V` | Verify the project |
|
|
575
|
+
| `q` or `ctrl+c` | Quit (stops the processes devcc started) |
|
|
576
|
+
|
|
577
|
+
### Processes and Services
|
|
578
|
+
|
|
579
|
+
| Key | Action |
|
|
580
|
+
| ------- | ---------------------------------- |
|
|
581
|
+
| `s` | Start or stop the selection |
|
|
582
|
+
| `r` | Restart the selection |
|
|
583
|
+
| `i` | Inspect the selection |
|
|
584
|
+
| `enter` | Jump to that process's logs |
|
|
585
|
+
| `d` | `docker compose down` (confirmed) |
|
|
586
|
+
| `o` | SSH to the selected remote machine |
|
|
587
|
+
|
|
588
|
+
### Worktrees
|
|
589
|
+
|
|
590
|
+
| Key | Action |
|
|
591
|
+
| ----------- | ------------------------------------------------------ |
|
|
592
|
+
| `n` | New worktree (branch, base, directory) |
|
|
593
|
+
| `d` | Remove the worktree (confirmed, never forced) |
|
|
594
|
+
| `o` / enter | Open the worktree in devcc; on an agent, its logs |
|
|
595
|
+
| `t` / `e` | Open a terminal / your editor in the worktree |
|
|
596
|
+
| `c` / `x` | Launch Claude Code / Codex with a task in the worktree |
|
|
597
|
+
| `s` | Stop the selected agent |
|
|
598
|
+
| `r` | Refresh the list |
|
|
599
|
+
|
|
600
|
+
### Scripts
|
|
601
|
+
|
|
602
|
+
| Key | Action |
|
|
603
|
+
| --------- | ---------------------------------- |
|
|
604
|
+
| `enter` | Run the selected script |
|
|
605
|
+
| `x` | Stop a running script |
|
|
606
|
+
| `f` / `c` | Filter the list / clear the filter |
|
|
607
|
+
|
|
608
|
+
### Git
|
|
609
|
+
|
|
610
|
+
| Key | Action |
|
|
611
|
+
| --------------- | --------------------------------- |
|
|
612
|
+
| `s` / `u` | Stage / unstage the selected file |
|
|
613
|
+
| `c` | Commit staged changes |
|
|
614
|
+
| `f` | Fetch |
|
|
615
|
+
| `p` / `shift+P` | Pull / push (push is confirmed) |
|
|
616
|
+
| `d` | Discard file changes (confirmed) |
|
|
617
|
+
| `r` | Refresh status |
|
|
618
|
+
|
|
619
|
+
### Logs
|
|
620
|
+
|
|
621
|
+
| Key | Action |
|
|
622
|
+
| ---------------- | -------------------------------------------------- |
|
|
623
|
+
| `j` / `k` | Scroll |
|
|
624
|
+
| `PgUp` / `PgDn` | Page |
|
|
625
|
+
| `home` / `end` | Jump to start / end |
|
|
626
|
+
| `f` | Toggle follow |
|
|
627
|
+
| `s` | Search: plain text, or a regex if it parses |
|
|
628
|
+
| `x` | Clear the search |
|
|
629
|
+
| `e` | Toggle errors only (stderr) |
|
|
630
|
+
| `a` | Merged stream of every source, colour-keyed |
|
|
631
|
+
| `tab`, `←` / `→` | Change log source |
|
|
632
|
+
| `c` | Clear the current buffer (all, in the merged view) |
|
|
633
|
+
|
|
634
|
+
### Dependencies
|
|
459
635
|
|
|
460
|
-
|
|
636
|
+
| Key | Action |
|
|
637
|
+
| --- | --------------------------------------- |
|
|
638
|
+
| `r` | Check the registry for updates |
|
|
639
|
+
| `u` | Update the selected package (confirmed) |
|
|
640
|
+
|
|
641
|
+
## Known limitations
|
|
642
|
+
|
|
643
|
+
- **Runtime.** The dashboard needs Bun, or Node ≥ 26.4 with `--experimental-ffi`. This is an OpenTUI/FFI
|
|
644
|
+
constraint, not a design choice.
|
|
645
|
+
- **Services.** Adapters ship for Docker Compose, PostgreSQL, Redis, Ollama (local or remote), Tailscale,
|
|
646
|
+
SSH machines and HTTP/port services. Others (Kubernetes, Vercel, Azure, …) are designed for but not
|
|
647
|
+
implemented.
|
|
648
|
+
- **Agents run headless.** Claude Code and Codex are started in their non-interactive modes with a task;
|
|
649
|
+
devcc cannot host their interactive interfaces. Use `t` for a terminal in the worktree instead.
|
|
650
|
+
- **Opening things outside devcc.** On macOS, terminals, editors and SSH use `open`. Elsewhere, set
|
|
651
|
+
`editor.command` and `terminal.command` (with `execArgs` for SSH).
|
|
652
|
+
- **direnv "loaded"** describes devcc's own environment (whether you started it from a direnv-enabled
|
|
653
|
+
shell), not your other terminals.
|
|
654
|
+
- **Remote reachability** is a TCP connection to the SSH port. It does not log in, so a machine that
|
|
655
|
+
accepts connections but rejects your key still shows as reachable.
|
|
656
|
+
- **Git.** The panel covers status, staging, discard, commit, fetch, pull and push. Branch switching,
|
|
657
|
+
rebasing, merge-conflict resolution and diff viewing are not implemented.
|
|
658
|
+
- **Detected services are read-only.** devcc will not start or stop something it did not launch, apart
|
|
659
|
+
from Docker Compose. `docker compose down --volumes` is deliberately not bound to a key.
|
|
660
|
+
- **Mouse.** Whatever OpenTUI provides by default; the interface is designed and tested for the keyboard.
|
|
661
|
+
- **Small terminals.** Below roughly 60 columns the sidebar hides and columns are trimmed. The layout
|
|
662
|
+
degrades rather than breaking, but it is cramped.
|
|
663
|
+
|
|
664
|
+
## Contributing
|
|
665
|
+
|
|
666
|
+
### Running from source
|
|
667
|
+
|
|
668
|
+
```bash
|
|
669
|
+
git clone https://github.com/dordevgit/devcc.git
|
|
670
|
+
cd devcc
|
|
671
|
+
pnpm install
|
|
672
|
+
pnpm dev:center # launch against this repo
|
|
673
|
+
node bin/devcc.mjs -C ~/code/example.com # or against another project
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
This repository's own [`.devcc.ts`](.devcc.ts) is a working config example.
|
|
677
|
+
|
|
678
|
+
### Scripts
|
|
679
|
+
|
|
680
|
+
```bash
|
|
681
|
+
pnpm lint # eslint (flat config, type-checked rules)
|
|
682
|
+
pnpm typecheck # tsc --noEmit, strict
|
|
683
|
+
pnpm test # vitest: core logic, no terminal required
|
|
684
|
+
pnpm test:tui # end-to-end smoke test against OpenTUI's headless renderer (Bun only)
|
|
685
|
+
pnpm build # tsc -> dist/
|
|
686
|
+
pnpm verify # lint + typecheck + test + build
|
|
687
|
+
pnpm format # prettier
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
`pnpm test` covers the non-UI core: package-manager detection, config parsing and validation, the command
|
|
691
|
+
registry, the log ring buffer, process state transitions and real process lifecycles, service detection
|
|
692
|
+
and adapter failure handling, git porcelain and worktree parsing (plus create/remove against a real
|
|
693
|
+
repository), agent launching, tool/mise/direnv detection, verification and its CLI exit codes, Tailscale
|
|
694
|
+
and remote Ollama parsing, the observable store, and the formatting helpers. No optional tool (Claude,
|
|
695
|
+
Codex, Ollama, Tailscale, mise, direnv) needs to be installed.
|
|
696
|
+
|
|
697
|
+
`pnpm test:tui` boots the real application against OpenTUI's test renderer and drives it with synthetic
|
|
698
|
+
keystrokes: navigation, palette, help, starting/restarting/stopping a managed process, running a package
|
|
699
|
+
script, log capture, creating and removing worktrees, launching an agent in a worktree, verification, and
|
|
700
|
+
clean shutdown. It asserts on behaviour rather than on frame snapshots.
|
|
701
|
+
|
|
702
|
+
### Architecture
|
|
461
703
|
|
|
462
704
|
```
|
|
463
705
|
src/devcc/
|
|
464
|
-
cli.ts argv parsing, TTY check,
|
|
706
|
+
cli.ts argv parsing, subcommands, TTY check, exit code
|
|
707
|
+
automation.ts devcc verify / worktree list / env (no TUI, JSON output)
|
|
465
708
|
index.ts public API (defineConfig, App, all reusable pieces)
|
|
466
709
|
|
|
467
710
|
app/
|
|
468
711
|
App.ts composition root: renderer, services, state, input
|
|
469
712
|
builtinCommands.ts the built-in command set
|
|
713
|
+
controlPlaneCommands.ts worktree, agent, verify, environment and remote commands
|
|
470
714
|
keymap.ts global bindings + the help cheat sheet
|
|
471
715
|
theme.ts palette and status glyphs
|
|
472
716
|
|
|
@@ -478,25 +722,26 @@ src/devcc/
|
|
|
478
722
|
|
|
479
723
|
components/ Header, Footer, Sidebar, RowList, StatusBadge, Overlay,
|
|
480
724
|
ConfirmDialog, CommandPalette, ProjectPicker, HelpOverlay
|
|
481
|
-
views/ Overview, Processes, Services, Scripts, Git,
|
|
482
|
-
Dependencies, System, Settings (all extend View.ts)
|
|
725
|
+
views/ Overview, Processes, Services, Scripts, Git, Worktrees,
|
|
726
|
+
Logs, Dependencies, System, Settings (all extend View.ts)
|
|
483
727
|
|
|
484
|
-
processes/ ManagedProcess types
|
|
728
|
+
processes/ ManagedProcess types, ProcessManager (incl. crash policy),
|
|
729
|
+
graph.ts: dependsOn planner (waves + cycle detection)
|
|
485
730
|
services/ ServiceAdapter interface, ServiceManager, and the
|
|
486
|
-
docker / node / postgres / redis / ollama adapters
|
|
731
|
+
docker / node / postgres / redis / ollama adapters,
|
|
732
|
+
remote.ts: SSH machines + Tailscale
|
|
733
|
+
git/ GitService, pure porcelain-v2 parsers, worktrees.ts
|
|
734
|
+
agents/ AgentAdapter (Claude Code, Codex, custom) + AgentManager
|
|
735
|
+
environment/ tool detection, mise/direnv parsers, EnvironmentService
|
|
736
|
+
verify/ step resolution, the runner loop, the spawn executor
|
|
737
|
+
platform/ editor / terminal / SSH launch commands
|
|
738
|
+
logs/ LogBuffer ring buffer, LogStore, merge.ts (merged stream, search)
|
|
487
739
|
deps/ DependencyService + per-manager `outdated` parsers
|
|
488
740
|
projects/ ProjectRegistry: discovery, recents, switcher list
|
|
489
|
-
processes/graph.ts dependsOn planner (waves + cycle detection)
|
|
490
|
-
logs/merge.ts merged stream, search filter
|
|
491
|
-
git/ GitService + pure porcelain-v2 parsers
|
|
492
741
|
system/ SystemMonitor (Node APIs only)
|
|
493
|
-
|
|
494
|
-
utils/ exec, packageManager, paths, format, fuzzy, logger,
|
|
495
|
-
errors
|
|
742
|
+
utils/ exec, packageManager, paths, format, fuzzy, logger, errors
|
|
496
743
|
```
|
|
497
744
|
|
|
498
|
-
### How data flows
|
|
499
|
-
|
|
500
745
|
```
|
|
501
746
|
ProcessManager ─┐
|
|
502
747
|
ServiceManager ─┤ typed events ┌─────────┐ watched slices ┌───────┐
|
|
@@ -505,65 +750,61 @@ SystemMonitor ─┤ └─────────┘
|
|
|
505
750
|
LogStore ─┘
|
|
506
751
|
```
|
|
507
752
|
|
|
508
|
-
Backends never touch renderables. They emit typed events; `App` folds those into
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
panel. List rendering recycles `TextRenderable`s and only materialises the rows
|
|
753
|
+
Backends never touch renderables. They emit typed events; `App` folds those into a single `AppState`;
|
|
754
|
+
views subscribe to the slices they care about via `store.watch(selector, listener)`, so a 1 Hz CPU sample
|
|
755
|
+
does not repaint the git panel. List rendering recycles `TextRenderable`s and only materialises the rows
|
|
512
756
|
that fit the viewport.
|
|
513
757
|
|
|
514
|
-
### Design decisions
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
- **Detected ≠ owned.** A process devcc launched is `ownership: "managed"`.
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
-
|
|
527
|
-
|
|
528
|
-
`
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
- **
|
|
541
|
-
|
|
758
|
+
### Design decisions
|
|
759
|
+
|
|
760
|
+
How the worktree, agent, environment, verification and remote features fit onto the existing abstractions
|
|
761
|
+
is written up in [docs/control-plane.md](docs/control-plane.md).
|
|
762
|
+
|
|
763
|
+
**Safety**
|
|
764
|
+
|
|
765
|
+
- **Nothing runs through a shell.** Every child process is `spawn(executable, args[])`, so arguments
|
|
766
|
+
containing spaces or quotes cannot become injection.
|
|
767
|
+
- **Detected ≠ owned.** A process devcc launched is `ownership: "managed"`. Anything merely observed on the
|
|
768
|
+
host is `"detected"` and can never be signalled by devcc.
|
|
769
|
+
- **Destructive actions are always confirmed:** `git restore`, `git push`, `docker compose down`, stop-all,
|
|
770
|
+
clear-all-logs, and any config command marked `confirm`. Discarding untracked files is refused outright.
|
|
771
|
+
- **Process trees die properly.** Children are spawned detached (their own process group) and stopped with
|
|
772
|
+
`kill(-pgid, SIGTERM)`, escalating to `SIGKILL` after the grace period, so dev servers do not leave
|
|
773
|
+
orphaned workers behind.
|
|
774
|
+
|
|
775
|
+
**Performance**
|
|
776
|
+
|
|
777
|
+
- **Startup never blocks.** The first frame renders before git, Docker, service detection or tool versions
|
|
778
|
+
have answered; each populates asynchronously with its own timeout.
|
|
779
|
+
- **Memory is bounded.** Each log source is a fixed-capacity ring buffer (5000 lines by default). The
|
|
780
|
+
merged view materialises at most 2,000 recent lines on demand. Search is plain substring, or a regex when
|
|
781
|
+
the query parses as one, so typing `(` never breaks the view.
|
|
782
|
+
- **Dependency checks never poll.** They reach the network, so they run only when you ask, and updating a
|
|
783
|
+
package is confirmed because it rewrites the lockfile.
|
|
784
|
+
- **Remote checks are rate-limited.** An adapter can set `refreshIntervalMs`; the poller skips it until that
|
|
785
|
+
has passed, so an open dashboard does not keep hitting a remote machine. Explicit refresh ignores it.
|
|
786
|
+
- **Agents are processes.** An agent adapter only describes a command line; the session is a managed task
|
|
787
|
+
in the same `ProcessManager`, so status, logs, stop and shutdown work exactly as for anything else.
|
|
788
|
+
|
|
789
|
+
**Structure**
|
|
790
|
+
|
|
791
|
+
- **Starts are ordered.** `dependsOn` and `readiness` turn "start all" into a wave-by-wave bring-up. The
|
|
542
792
|
ordering is a pure function (`planStartOrder`) with its own tests.
|
|
543
|
-
- **
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
you ask, and updating a package is confirmed because it rewrites the lockfile.
|
|
556
|
-
- **Errors are never swallowed.** They are normalised into `DevccError`, written
|
|
557
|
-
to `.devcc/devcc.log`, shown in the footer, and kept for inspection in
|
|
558
|
-
**Settings → Diagnostics**.
|
|
559
|
-
|
|
560
|
-
## Extension points
|
|
561
|
-
|
|
562
|
-
**Add a command** - register it once and it appears in the palette, with an
|
|
563
|
-
optional confirmation gate:
|
|
793
|
+
- **Several projects stay open.** Each open project keeps its processes and log capture alive in the
|
|
794
|
+
background; only the visible one polls git, services and system. Closing a project (or quitting) stops
|
|
795
|
+
what devcc started there, with a confirmation.
|
|
796
|
+
- **Switching project rebuilds the session, not the UI.** The renderer, views and store survive; the
|
|
797
|
+
process manager, service adapters, git service, logger and command registry are rebuilt for the new
|
|
798
|
+
directory.
|
|
799
|
+
- **Errors are never swallowed.** They are normalised into `DevccError`, written to `.devcc/devcc.log`,
|
|
800
|
+
shown in the footer, and kept for inspection in **Settings → Diagnostics**.
|
|
801
|
+
|
|
802
|
+
### Extending devcc
|
|
803
|
+
|
|
804
|
+
**Add a command.** Register it once and it appears in the palette, with an optional confirmation gate:
|
|
564
805
|
|
|
565
806
|
```ts
|
|
566
|
-
import { type CommandDefinition } from "
|
|
807
|
+
import { type CommandDefinition } from "@doriandev/devcc"
|
|
567
808
|
|
|
568
809
|
const command: CommandDefinition = {
|
|
569
810
|
id: "deploy.preview",
|
|
@@ -578,15 +819,15 @@ const command: CommandDefinition = {
|
|
|
578
819
|
}
|
|
579
820
|
```
|
|
580
821
|
|
|
581
|
-
`CommandContext` exposes the store, the process/service/git/log/system services,
|
|
582
|
-
|
|
822
|
+
`CommandContext` exposes the store, the process/service/git/log/system services, and `navigate`,
|
|
823
|
+
`notify`, `confirm`, `prompt`, `runScript` and `quit`.
|
|
583
824
|
|
|
584
|
-
**Add a service adapter
|
|
585
|
-
`
|
|
586
|
-
|
|
825
|
+
**Add a service adapter.** Implement `ServiceAdapter` and register it with the `ServiceManager`.
|
|
826
|
+
`detect()` decides whether the service is relevant at all, so adapters cost nothing in projects that do not
|
|
827
|
+
use them:
|
|
587
828
|
|
|
588
829
|
```ts
|
|
589
|
-
import { type ServiceAdapter } from "
|
|
830
|
+
import { type ServiceAdapter } from "@doriandev/devcc"
|
|
590
831
|
|
|
591
832
|
export class TailscaleService implements ServiceAdapter {
|
|
592
833
|
readonly id = "tailscale"
|
|
@@ -608,52 +849,11 @@ export class TailscaleService implements ServiceAdapter {
|
|
|
608
849
|
}
|
|
609
850
|
```
|
|
610
851
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
optional `start`/`stop`/`restart`.
|
|
614
|
-
|
|
615
|
-
**Add a view** - extend `views/View.ts`, register it in `App`, and add an entry
|
|
616
|
-
to `SIDEBAR_ITEMS`.
|
|
617
|
-
|
|
618
|
-
## Development
|
|
619
|
-
|
|
620
|
-
```bash
|
|
621
|
-
pnpm lint # eslint (flat config, type-checked rules)
|
|
622
|
-
pnpm typecheck # tsc --noEmit, strict
|
|
623
|
-
pnpm test # vitest - core logic, no terminal required
|
|
624
|
-
pnpm test:tui # end-to-end smoke test against OpenTUI's headless renderer
|
|
625
|
-
pnpm build # tsc -> dist/
|
|
626
|
-
pnpm verify # lint + typecheck + test + build
|
|
627
|
-
pnpm format # prettier
|
|
628
|
-
```
|
|
629
|
-
|
|
630
|
-
`pnpm test` covers the non-UI core: package-manager detection, config parsing
|
|
631
|
-
and validation, the command registry, the log ring buffer, process state
|
|
632
|
-
transitions and real process lifecycles, service detection and adapter failure
|
|
633
|
-
handling, git porcelain parsing, the observable store, and the formatting
|
|
634
|
-
helpers.
|
|
852
|
+
Azure, Vercel, GitHub, Kubernetes, remote SSH hosts or CI pipelines would be added the same way: a
|
|
853
|
+
`detect()` plus a `getStatus()`, with optional `start`/`stop`/`restart`.
|
|
635
854
|
|
|
636
|
-
|
|
637
|
-
renderer (Bun only) and drives it with synthetic keystrokes: navigation,
|
|
638
|
-
palette, help, starting/restarting/stopping a managed process, running a
|
|
639
|
-
package script, log capture, and clean shutdown. It asserts on behaviour rather
|
|
640
|
-
than on frame snapshots.
|
|
855
|
+
**Add a view.** Extend `views/View.ts`, register it in `App`, and add an entry to `SIDEBAR_ITEMS`.
|
|
641
856
|
|
|
642
|
-
##
|
|
857
|
+
## License
|
|
643
858
|
|
|
644
|
-
|
|
645
|
-
this is an OpenTUI/FFI constraint, not a design choice.
|
|
646
|
-
- Service adapters ship for Docker Compose, PostgreSQL, Redis, Ollama and
|
|
647
|
-
HTTP/port services. Others (Kubernetes, Vercel, Azure, Tailscale, …) are
|
|
648
|
-
designed for but not implemented.
|
|
649
|
-
- The Git panel covers status, staging, discard, commit, fetch, pull and push.
|
|
650
|
-
Branch switching, rebasing, merge-conflict resolution and diff viewing in the
|
|
651
|
-
UI are not implemented (`GitService.diff()` exists but has no view yet).
|
|
652
|
-
- Detected services are read-only: devcc will not start or stop something it did
|
|
653
|
-
not launch, apart from Docker Compose.
|
|
654
|
-
- `docker compose down --volumes` is available through `DockerService.down()`
|
|
655
|
-
but is deliberately not bound to a key.
|
|
656
|
-
- Mouse support is whatever OpenTUI provides by default; the interface is
|
|
657
|
-
designed and tested for the keyboard.
|
|
658
|
-
- Below roughly 60 columns the sidebar hides and columns are trimmed; the layout
|
|
659
|
-
degrades rather than breaking, but very small terminals are cramped.
|
|
859
|
+
[ISC](LICENSE)
|