termdeck-cli 1.0.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/README.md +233 -0
- package/bin/termdeck.js +22 -0
- package/package.json +39 -0
- package/src/config.js +427 -0
- package/src/dashboard.js +542 -0
- package/src/devServer.js +246 -0
- package/src/index.js +164 -0
- package/src/logView.js +194 -0
- package/src/terminal.js +175 -0
- package/src/util.js +218 -0
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# termdeck
|
|
2
|
+
|
|
3
|
+
A terminal dashboard (TUI) for juggling your local dev projects.
|
|
4
|
+
|
|
5
|
+
One screen lists your projects with a colour-coded status and blurb, and gives
|
|
6
|
+
each one three actions:
|
|
7
|
+
|
|
8
|
+
| CTA | What it does |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| **Dev Server** | runs `npm run dev` **inside termdeck** — stdout/stderr stream into the scrollable log pane below (no extra terminal window), then the localhost URL is detected and opened in your default browser |
|
|
11
|
+
| **Editor** | opens a **brand new OS terminal window**, `cd`s into the project and runs `code .` |
|
|
12
|
+
| **Agent** | opens a **brand new OS terminal window**, `cd`s into the project and runs `opencode` (placeholder — configurable) |
|
|
13
|
+
|
|
14
|
+
Everything is keyboard driven *and* mouse driven: the three CTAs are clickable
|
|
15
|
+
buttons, the project list is click-selectable, and the mouse wheel scrolls the
|
|
16
|
+
logs.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
+----------------------------------------------------------------------+
|
|
20
|
+
| termdeck 4 projects · /home/you/Projects ● 2 dev servers running
|
|
21
|
+
+------------------------+---------------------------------------------+
|
|
22
|
+
| projects | selected project |
|
|
23
|
+
| ● api [Live] | alpha ● Working |
|
|
24
|
+
| ● alpha [Working] | /home/you/Projects/alpha |
|
|
25
|
+
| ○ blog [Pending] | marketing site |
|
|
26
|
+
| ○ lab [Experiment]| editor: code . agent: opencode |
|
|
27
|
+
| | ● dev server running (pid 8123) → localhost |
|
|
28
|
+
+------------------------+---------------------------------------------+
|
|
29
|
+
| | [d] Dev Server [e] Editor [a] Agent |
|
|
30
|
+
| +---------------------------------------------+
|
|
31
|
+
| | dev server logs |
|
|
32
|
+
| | 12:04:11 alpha [termdeck] $npm run dev |
|
|
33
|
+
| | 12:04:12 alpha ➜ Local: http://localhost:51 |
|
|
34
|
+
+------------------------+---------------------------------------------+
|
|
35
|
+
| ↑/↓ select d dev e editor a agent x stop r reload q quit |
|
|
36
|
+
+----------------------------------------------------------------------+
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g termdeck
|
|
43
|
+
termdeck
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Requires Node.js 16+ and a real terminal (macOS/Linux Terminal, Windows
|
|
47
|
+
Terminal, iTerm, …). No Docker, no daemon, no background service.
|
|
48
|
+
|
|
49
|
+
## First run
|
|
50
|
+
|
|
51
|
+
The first launch asks a few questions and remembers the answers in
|
|
52
|
+
`~/.termdeck-config.json`:
|
|
53
|
+
|
|
54
|
+
1. **Which directory holds your projects?** — pick from suggestions (common
|
|
55
|
+
folders like `~/Projects`, plus every drive letter on Windows) or type a path.
|
|
56
|
+
2. **Which folders are projects?** — multi-select with <kbd>space</kbd>, confirm
|
|
57
|
+
with <kbd>enter</kbd>.
|
|
58
|
+
3. **Status + description per folder** — `Experimental`, `Live`, `Working` or
|
|
59
|
+
`Pending`, plus a one line blurb.
|
|
60
|
+
|
|
61
|
+
Every later launch skips straight to the dashboard. Re-run it any time with
|
|
62
|
+
`termdeck --setup` (existing answers are pre-filled as defaults).
|
|
63
|
+
|
|
64
|
+
## Keys
|
|
65
|
+
|
|
66
|
+
| Key | Action |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| <kbd>↑</kbd>/<kbd>↓</kbd>, <kbd>j</kbd>/<kbd>k</kbd> | select a project (or click it) |
|
|
69
|
+
| <kbd>d</kbd> | start the dev server for the selection (or click **Dev Server**) |
|
|
70
|
+
| <kbd>e</kbd> | open the editor in a new terminal window (or click **Editor**) |
|
|
71
|
+
| <kbd>a</kbd> | open the agent in a new terminal window (or click **Agent**) |
|
|
72
|
+
| <kbd>x</kbd> | stop the selected project's dev server |
|
|
73
|
+
| <kbd>r</kbd> | reload the config file from disk |
|
|
74
|
+
| <kbd>PgUp</kbd>/<kbd>PgDn</kbd>, wheel | scroll the log pane (pauses following, shows how many lines arrived) |
|
|
75
|
+
| <kbd>shift</kbd>+<kbd>G</kbd>, <kbd>end</kbd> | jump back to live logs |
|
|
76
|
+
| <kbd>home</kbd> | jump to the start of the log history |
|
|
77
|
+
| <kbd>q</kbd>, <kbd>ctrl</kbd>+<kbd>c</kbd> | quit — every dev server termdeck started is stopped first |
|
|
78
|
+
|
|
79
|
+
Quitting while dev servers are running asks for a second <kbd>q</kbd> press.
|
|
80
|
+
|
|
81
|
+
## CLI
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
termdeck launch the dashboard (runs setup on first use)
|
|
85
|
+
termdeck --setup re-run the setup wizard
|
|
86
|
+
termdeck --reset delete the config file, then run setup again
|
|
87
|
+
termdeck --list print the configured projects and exit (no TUI)
|
|
88
|
+
termdeck --no-open never auto-open the browser
|
|
89
|
+
termdeck --help
|
|
90
|
+
termdeck --version
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Config file
|
|
94
|
+
|
|
95
|
+
`~/.termdeck-config.json` (override the path with the `TERMDECK_CONFIG`
|
|
96
|
+
environment variable):
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"version": 1,
|
|
101
|
+
"root": "/home/you/Projects",
|
|
102
|
+
"devCommand": "npm run dev",
|
|
103
|
+
"editorCommand": "code .",
|
|
104
|
+
"agentCommand": "opencode",
|
|
105
|
+
"openBrowser": true,
|
|
106
|
+
"projects": [
|
|
107
|
+
{
|
|
108
|
+
"name": "alpha",
|
|
109
|
+
"path": "/home/you/Projects/alpha",
|
|
110
|
+
"status": "Working",
|
|
111
|
+
"info": "marketing site with a Next.js frontend"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The same keys can be set **per project** inside a `projects[]` entry
|
|
118
|
+
(`devCommand`, `editorCommand`, `agentCommand`, `port`), which is handy when one
|
|
119
|
+
repo needs `pnpm dev`, `npm start` or a fixed port. Editing the file by hand is
|
|
120
|
+
fine — press <kbd>r</kbd> in the dashboard to reload it.
|
|
121
|
+
|
|
122
|
+
| Field | Meaning |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| `devCommand` | command run for the Dev Server CTA (default `npm run dev`) |
|
|
125
|
+
| `editorCommand` | command run in the new editor terminal (default `code .`) |
|
|
126
|
+
| `agentCommand` | command run in the new agent terminal (default `opencode`) |
|
|
127
|
+
| `openBrowser` | set to `false` (or pass `--no-open`) to keep the browser closed |
|
|
128
|
+
| `port` | fallback port used if the dev server never prints a URL (default `3000`) |
|
|
129
|
+
| `status` | `Experimental` · `Live` · `Working` · `Pending` |
|
|
130
|
+
|
|
131
|
+
## How each CTA works
|
|
132
|
+
|
|
133
|
+
**Dev Server (in-app logs).** `cross-spawn` runs the dev command with `cwd` set
|
|
134
|
+
to the project, `stdio: ['ignore','pipe','pipe']` and `FORCE_COLOR=0`, so nothing
|
|
135
|
+
is attached to a terminal. Each stream is split into lines and pushed into the
|
|
136
|
+
blessed-contrib `log` widget in the dashboard (batched every 120 ms — dev
|
|
137
|
+
servers can emit hundreds of lines per second). Every line is scanned for a
|
|
138
|
+
localhost URL (`http://localhost:5173/`, `0.0.0.0:3000`, `listening on port
|
|
139
|
+
4200`, …); the first hit is normalised, and after a short delay the `open`
|
|
140
|
+
package launches your default browser. If no URL shows up within ~9 seconds,
|
|
141
|
+
termdeck assumes `http://localhost:<port || 3000>` and says so in the log pane.
|
|
142
|
+
Processes are spawned detached on macOS/Linux and killed as a tree
|
|
143
|
+
(`process.kill(-pid)` / `taskkill /T /F`), so a quit never leaves an orphaned
|
|
144
|
+
Vite/Next server behind.
|
|
145
|
+
|
|
146
|
+
**Editor / Agent (new terminal windows).** `cross-spawn` launches the OS
|
|
147
|
+
terminal:
|
|
148
|
+
|
|
149
|
+
- **macOS** — `osascript -e 'tell application "Terminal" … do script "cd … && code ."'`
|
|
150
|
+
- **Windows** — `wt.exe -d "<dir>" cmd /k "code ."`, falling back to
|
|
151
|
+
`cmd /c start "" /D "<dir>" cmd.exe /k "code ."` when Windows Terminal is not
|
|
152
|
+
installed
|
|
153
|
+
- **Linux** — the first emulator found on `PATH` out of `gnome-terminal`,
|
|
154
|
+
`konsole`, `xfce4-terminal`, `kitty`, `alacritty`, `wezterm`,
|
|
155
|
+
`x-terminal-emulator`, `xterm` (each gets `--working-directory`/`-e` with
|
|
156
|
+
`bash -lc` and `exec bash` so the window stays open)
|
|
157
|
+
|
|
158
|
+
On Linux you can force a specific emulator with the `TERMDECK_TERMINAL`
|
|
159
|
+
environment variable.
|
|
160
|
+
|
|
161
|
+
## Linking locally (test before publishing)
|
|
162
|
+
|
|
163
|
+
From the project folder:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm install # install dependencies
|
|
167
|
+
npm test # unit + end-to-end dev server tests (no TUI needed)
|
|
168
|
+
npm run smoke # headless TUI smoke test: renders the dashboard, clicks a CTA
|
|
169
|
+
|
|
170
|
+
npm link # symlinks this package into your global node_modules
|
|
171
|
+
termdeck # now runs from anywhere with your edits live
|
|
172
|
+
|
|
173
|
+
# when you are done
|
|
174
|
+
npm unlink -g termdeck
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`npm link` creates a global `termdeck` shim that points at this directory, so
|
|
178
|
+
code changes take effect immediately — no republishing. If you would rather not
|
|
179
|
+
touch the global install, these work too:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm install -g . # real global install from the folder
|
|
183
|
+
node bin/termdeck.js # run the entry point directly
|
|
184
|
+
npm exec -- termdeck # run via the local package
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Two tips while testing:
|
|
188
|
+
|
|
189
|
+
- Keep your real config safe by pointing at a throwaway one:
|
|
190
|
+
`TERMDECK_CONFIG=./scratch-config.json termdeck` (on Windows Git Bash use
|
|
191
|
+
`TERMDECK_CONFIG=./scratch-config.json node bin/termdeck.js`).
|
|
192
|
+
- `termdeck --list` prints the parsed config without starting the TUI, which is
|
|
193
|
+
the quickest way to check that setup wrote what you expected.
|
|
194
|
+
|
|
195
|
+
When you are ready to publish:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm pack --dry-run # inspect exactly which files would be uploaded
|
|
199
|
+
npm publish # needs an npm account; the package name must be free
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The `bin` field in `package.json` plus the `#!/usr/bin/env node` shebang in
|
|
203
|
+
`bin/termdeck.js` are what make the global `termdeck` command work.
|
|
204
|
+
|
|
205
|
+
## Troubleshooting
|
|
206
|
+
|
|
207
|
+
| Symptom | Fix |
|
|
208
|
+
| --- | --- |
|
|
209
|
+
| `termdeck needs an interactive terminal` | first-run setup and the dashboard need a TTY. Use a real terminal, or `termdeck --list` |
|
|
210
|
+
| Browser opens too early / too late | tune the port: the URL is only opened once it appears in the output. Silence your dev server's URL banner and termdeck falls back after ~9s |
|
|
211
|
+
| "no terminal emulator found" | install one of the Linux terminals above or set `TERMDECK_TERMINAL` |
|
|
212
|
+
| `opencode` not found in the new window | change `agentCommand` to whatever you use (`cursor .`, `claude`, `aider`, …) |
|
|
213
|
+
| Log colours look plain | intentional: ANSI codes are stripped so the log pane stays readable in a terminal multiplexer |
|
|
214
|
+
| Nothing appears when clicking | make sure you are *inside* the TUI window and the terminal reports mouse events (Windows Terminal, iTerm2, GNOME Terminal, VS Code all do) |
|
|
215
|
+
|
|
216
|
+
## Development
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
bin/termdeck.js shebang shim -> src/index.js
|
|
220
|
+
src/index.js CLI flags, setup-or-dashboard decision
|
|
221
|
+
src/config.js ~/.termdeck-config.json + the inquirer wizard
|
|
222
|
+
src/dashboard.js the blessed/blessed-contrib TUI
|
|
223
|
+
src/devServer.js spawn + log streaming + URL detection + browser open
|
|
224
|
+
src/terminal.js OS-specific "new terminal window" plans
|
|
225
|
+
src/logView.js scrollable, follow-the-tail log pane
|
|
226
|
+
src/util.js ANSI stripping, URL parsing, which(), killTree()
|
|
227
|
+
test/run.js npm test — unit tests + a real npm run dev lifecycle
|
|
228
|
+
test/smoke.js npm run smoke — headless render + real mouse click on a CTA
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT
|
package/bin/termdeck.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* termdeck binary entry point.
|
|
6
|
+
*
|
|
7
|
+
* The shebang above (plus the `bin` field in package.json) is what makes
|
|
8
|
+
* `npm i -g termdeck` give you a global `termdeck` command.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const { main } = require('../src/index.js');
|
|
12
|
+
|
|
13
|
+
main(process.argv.slice(2))
|
|
14
|
+
.then((code) => {
|
|
15
|
+
// The dashboard keeps the process alive; only surface real exit codes.
|
|
16
|
+
if (typeof code === 'number' && code !== 0) process.exitCode = code;
|
|
17
|
+
})
|
|
18
|
+
.catch((err) => {
|
|
19
|
+
const message = err && err.message ? err.message : String(err);
|
|
20
|
+
process.stderr.write(`termdeck: ${message}\n`);
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "termdeck-cli",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "A terminal dashboard for your local dev projects: start dev servers with in-app logs, open your editor, or launch a coding agent in a fresh terminal window.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"tui",
|
|
8
|
+
"dashboard",
|
|
9
|
+
"blessed",
|
|
10
|
+
"blessed-contrib",
|
|
11
|
+
"dev-server",
|
|
12
|
+
"projects"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"main": "src/index.js",
|
|
16
|
+
"bin": {
|
|
17
|
+
"termdeck": "bin/termdeck.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin",
|
|
21
|
+
"src",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=16"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"start": "node bin/termdeck.js",
|
|
29
|
+
"test": "node test/run.js",
|
|
30
|
+
"smoke": "node test/smoke.js"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"blessed": "^0.1.81",
|
|
34
|
+
"blessed-contrib": "^4.11.0",
|
|
35
|
+
"cross-spawn": "^7.0.3",
|
|
36
|
+
"inquirer": "^8.2.6",
|
|
37
|
+
"open": "^8.4.2"
|
|
38
|
+
}
|
|
39
|
+
}
|