@jhizzard/termdeck 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joshua Izzard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # TermDeck
2
+
3
+ ![TermDeck running 6 terminals in a 3x2 control room layout](assets/hero.jpg)
4
+
5
+ Web-based terminal multiplexer with AI-aware session management, rich metadata overlays, and cross-project RAG integration.
6
+
7
+ Think of it as tmux in your browser — but each terminal panel shows you what project it belongs to, what the AI is doing, and pipes everything into your memory system.
8
+
9
+ ![30 second demo](assets/demo.gif)
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npx @jhizzard/termdeck
15
+ ```
16
+
17
+ That's it — the published package ships prebuilt binaries for `node-pty` and `better-sqlite3`, so you don't need a C++ toolchain for the common path (Node 20/22/24 on macOS, Linux, Windows).
18
+
19
+ ### From source
20
+
21
+ ```bash
22
+ git clone https://github.com/jhizzard/termdeck.git
23
+ cd termdeck
24
+ npm install
25
+ npm run dev
26
+ ```
27
+
28
+ ### Prerequisites for source builds only
29
+
30
+ If prebuilt binaries are unavailable for your platform (rare), TermDeck falls back to compiling [node-pty](https://github.com/microsoft/node-pty) locally. In that case you'll need:
31
+
32
+ - **macOS**: `xcode-select --install` (installs Xcode Command Line Tools)
33
+ - **Windows**: Install [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) with the "Desktop development with C++" workload
34
+ - **Linux (Debian/Ubuntu)**: `sudo apt install build-essential python3`
35
+ - **Linux (Fedora)**: `sudo dnf groupinstall "Development Tools"`
36
+
37
+ If `npm install` fails with errors mentioning `node-gyp`, `gyp`, or `node-pty`, you're missing the compiler.
38
+
39
+ ### macOS
40
+ ```bash
41
+ npm run install:app
42
+ # Creates ~/Applications/TermDeck.app — double-click to launch, drag to Dock
43
+ ```
44
+
45
+ ### Windows
46
+ ```cmd
47
+ install.bat
48
+ # Creates Start Menu + Desktop shortcuts
49
+ ```
50
+
51
+ ### Linux
52
+ ```bash
53
+ npm run dev
54
+ # Or: node packages/cli/src/index.js
55
+ ```
56
+
57
+ No terminal needed after installation — TermDeck opens your browser automatically.
58
+
59
+ ## What it does
60
+
61
+ TermDeck gives you a single browser window with multiple embedded terminal panels. Each panel is a real PTY — full ANSI/VT100 support, so Claude Code, Gemini CLI, vim, htop, and any other terminal app works exactly as it would in a native terminal.
62
+
63
+ Each terminal panel has:
64
+
65
+ - **Status indicator** — green (active), purple (thinking), amber (idle), red (errored)
66
+ - **Type detection** — automatically identifies Claude Code, Gemini CLI, Python servers, or plain shells
67
+ - **Project tag** — color-coded project association
68
+ - **Metadata strip** — when opened, why, last commands, detected ports, request counts
69
+ - **Individual controls** — theme selector, focus/half/close, AI question input
70
+ - **Per-terminal theming** — Tokyo Night, Rose Pine Dawn, Catppuccin, Dracula, Nord, and more
71
+
72
+ ## Layout modes
73
+
74
+ Designed for iMac-scale screens. Layout modes let you see the right amount of detail:
75
+
76
+ | Mode | Grid | Use case |
77
+ |------|------|----------|
78
+ | 1x1 | Single terminal | Deep work with one AI agent |
79
+ | 2x1 | Two columns | Half-screen split |
80
+ | 2x2 | 2x2 grid | Four terminals at comfortable size |
81
+ | 3x2 | 3x2 grid | Six terminals, monitoring mode |
82
+ | 2x4 | 2x4 grid | Eight terminals, tall vertical pairs |
83
+ | 4x2 | 4x2 grid | Eight terminals, control room |
84
+ | Focus | One expanded | Temporarily expand any panel |
85
+ | Half | One large + stack | One primary + secondary panels |
86
+
87
+ ## Prompt bar
88
+
89
+ The bottom prompt bar launches new terminals:
90
+
91
+ ```
92
+ > bash # Plain shell
93
+ > claude code ~/my-project # Claude Code in a directory
94
+ > python3 manage.py runserver # Django dev server
95
+ > cc my-project # Shorthand: Claude Code + project
96
+ > gemini # Gemini CLI
97
+ > npx vitest run # One-shot command
98
+ ```
99
+
100
+ Select a project from the dropdown to auto-tag and auto-`cd` into the project directory.
101
+
102
+ ## Configuration
103
+
104
+ The installer creates `~/.termdeck/config.yaml`. Edit it to define your projects:
105
+
106
+ ```yaml
107
+ port: 3000
108
+ shell: /bin/zsh
109
+ defaultTheme: tokyo-night
110
+
111
+ projects:
112
+ my-project:
113
+ path: ~/code/my-project
114
+ defaultTheme: catppuccin-mocha
115
+ defaultCommand: claude
116
+
117
+ rag:
118
+ enabled: false
119
+ supabaseUrl: https://your-project.supabase.co
120
+ supabaseKey: your-anon-key
121
+ ```
122
+
123
+ ## RAG integration
124
+
125
+ TermDeck has a three-layer memory system:
126
+
127
+ 1. **Session memory** — what happened in each terminal session
128
+ 2. **Project memory** — commands, file edits, and patterns shared across sessions within a project
129
+ 3. **Developer memory** — cross-project patterns (your habits, common workflows, error resolutions)
130
+
131
+ Events are always recorded to local SQLite (`~/.termdeck/termdeck.db`). Enable Supabase sync by adding your credentials to the config file and running `config/supabase-migration.sql` in your Supabase SQL editor.
132
+
133
+ ## Keyboard shortcuts
134
+
135
+ | Shortcut | Action |
136
+ |----------|--------|
137
+ | Ctrl+Shift+N | Focus prompt bar |
138
+ | Ctrl+Shift+1 | Layout: 1x1 |
139
+ | Ctrl+Shift+2 | Layout: 2x1 |
140
+ | Ctrl+Shift+3 | Layout: 2x2 |
141
+ | Ctrl+Shift+4 | Layout: 3x2 |
142
+ | Ctrl+Shift+5 | Layout: 2x4 |
143
+ | Ctrl+Shift+6 | Layout: 4x2 |
144
+ | Ctrl+Shift+] | Next terminal |
145
+ | Ctrl+Shift+[ | Previous terminal |
146
+ | Escape | Exit focus/half mode |
147
+
148
+ ## Architecture
149
+
150
+ ```
151
+ Browser (xterm.js panels)
152
+ | WebSocket (1 per terminal)
153
+ Node.js server
154
+ |-- Session manager (create, destroy, metadata)
155
+ |-- WebSocket hub (mux terminal I/O)
156
+ |-- REST API (CRUD, resize, themes)
157
+ |-- Output analyzer (status detection)
158
+ |-- RAG event recorder (SQLite + Supabase sync)
159
+ | node-pty
160
+ OS pseudo-terminals
161
+ |-- bash/zsh
162
+ |-- Claude Code
163
+ |-- python3 servers
164
+ |-- Gemini CLI
165
+ |-- any CLI tool
166
+ |
167
+ SQLite (local) --sync--> Supabase (RAG)
168
+ ```
169
+
170
+ ## Security
171
+
172
+ TermDeck gives each terminal panel full shell access on your machine. It binds to `127.0.0.1` (localhost only) by default.
173
+
174
+ **Do NOT expose TermDeck to the network without authentication.** There is no built-in auth in v0.1. If you need remote access, put it behind a VPN or SSH tunnel.
175
+
176
+ ## Tech stack
177
+
178
+ - **Server**: Node.js, Express, node-pty, ws, better-sqlite3
179
+ - **Client**: xterm.js, xterm-addon-fit, vanilla JS (no build step)
180
+ - **Storage**: SQLite (local), Supabase/PostgreSQL (RAG)
181
+ - **Themes**: 8 curated terminal color schemes
182
+ - **Launch**: macOS .app bundle (no terminal needed)
183
+
184
+ ## How to test
185
+
186
+ After installing, verify each feature works:
187
+
188
+ 1. **Launch** — Double-click TermDeck.app or run `npm run dev`. Browser should open automatically.
189
+ 2. **Create terminals** — Type `bash` in the prompt bar and click Launch. Verify the terminal is interactive (`ls`, `pwd`, `echo hello`).
190
+ 3. **Multiple terminals** — Open 4+ terminals. Verify they're independent.
191
+ 4. **Layouts** — Click each layout button (1x1 through 4x2). Try Ctrl+Shift+1-6.
192
+ 5. **Focus/Half** — Click the focus (square) and half (rectangle) buttons on a panel. Press Escape to exit.
193
+ 6. **Keyboard nav** — Use Ctrl+Shift+] and [ to cycle between terminals.
194
+ 7. **Metadata** — Run commands and verify "last command" updates in the metadata strip.
195
+ 8. **Port detection** — Run `python3 -m http.server 8888`. Verify port shows in metadata and type changes to "Python Server".
196
+ 9. **Themes** — Change themes on two terminals independently via the dropdown.
197
+ 10. **Projects** — Select a project from the dropdown, launch a terminal. Verify it cd's to the right directory.
198
+ 11. **Terminal exit** — Type `exit` in a terminal. Panel should dim with "Exited (0)".
199
+ 12. **Persistence** — Restart the server. Old sessions should be marked as exited in the DB.
200
+ 13. **Command history** — Check `GET http://localhost:3000/api/sessions/:id/history`.
201
+ 14. **RAG events** — Check `GET http://localhost:3000/api/rag/events` to see recorded events.
202
+
203
+ ## Development
204
+
205
+ ```bash
206
+ # Install dependencies
207
+ npm install
208
+
209
+ # Run server directly
210
+ npm run server
211
+
212
+ # Run via CLI (opens browser)
213
+ npm run dev
214
+
215
+ # The client is served as static files from packages/client/public/
216
+ ```
217
+
218
+ ## Troubleshooting
219
+
220
+ ### `npm install` fails with node-gyp errors
221
+
222
+ Install the C++ compiler for your platform (see Prerequisites above), then:
223
+
224
+ ```bash
225
+ npm cache clean --force
226
+ rm -rf node_modules package-lock.json
227
+ npm install
228
+ ```
229
+
230
+ ### Terminal panels don't respond to input
231
+
232
+ Check that node-pty compiled correctly:
233
+
234
+ ```bash
235
+ node -e "require('node-pty')"
236
+ ```
237
+
238
+ If this throws an error, reinstall with: `npm rebuild node-pty`
239
+
240
+ ## License
241
+
242
+ MIT
@@ -0,0 +1,58 @@
1
+ # TermDeck Configuration
2
+ # Copy to ~/.termdeck/config.yaml and customize
3
+
4
+ port: 3000
5
+ host: 127.0.0.1
6
+ shell: /bin/zsh # or /bin/bash
7
+
8
+ defaultTheme: tokyo-night
9
+
10
+ # Project definitions
11
+ # Each project maps a name to a directory + defaults
12
+ # These appear in the prompt bar dropdown and enable auto-cd + default themes
13
+ projects:
14
+ # my-project:
15
+ # path: ~/code/my-project
16
+ # defaultTheme: catppuccin-mocha
17
+ # defaultCommand: claude # or bash, gemini, etc.
18
+ # another-project:
19
+ # path: ~/code/another-project
20
+ # defaultTheme: dracula
21
+ # defaultCommand: bash
22
+
23
+ # RAG Integration (Supabase)
24
+ # Multi-layer memory: session -> project -> developer
25
+ # Events are always recorded to local SQLite.
26
+ #
27
+ # Secrets live in ~/.termdeck/secrets.env (see config/secrets.env.example).
28
+ # Values below use ${VAR} substitution so this file stays free of secrets.
29
+ rag:
30
+ enabled: false
31
+ supabaseUrl: ${SUPABASE_URL}
32
+ supabaseKey: ${SUPABASE_SERVICE_ROLE_KEY}
33
+ openaiApiKey: ${OPENAI_API_KEY}
34
+ anthropicApiKey: ${ANTHROPIC_API_KEY}
35
+ # developerId: your-username (defaults to OS username)
36
+ syncIntervalMs: 10000
37
+
38
+ # Engram bridge — how /api/ai/query talks to @jhizzard/engram.
39
+ # direct — server embeds + queries Supabase itself (default, preserves v0.1 behavior)
40
+ # webhook — POST to a running `engram serve` HTTP webhook (see engramWebhookUrl)
41
+ # mcp — spawn the local `engram` binary and talk JSON-RPC over stdio
42
+ engramMode: direct
43
+ engramWebhookUrl: http://localhost:37778/engram
44
+ # engramBinary: engram # override path to the @jhizzard/engram CLI for mcp mode
45
+
46
+ # Supabase table names (created by config/supabase-migration.sql)
47
+ tables:
48
+ session: engram_session_memory
49
+ project: engram_project_memory
50
+ developer: engram_developer_memory
51
+ commands: engram_commands
52
+
53
+ # Per-session markdown logs written to ~/.termdeck/sessions/ on session exit.
54
+ # Zero-config: works without Supabase / OpenAI. Optional LLM summary requires
55
+ # ANTHROPIC_API_KEY (env or rag.anthropicApiKey). CLI flag: `termdeck --session-logs`.
56
+ sessionLogs:
57
+ enabled: false
58
+ summaryModel: claude-haiku-4-5
@@ -0,0 +1,17 @@
1
+ # TermDeck secrets (F2.2)
2
+ # Copy this file to ~/.termdeck/secrets.env and fill in the values.
3
+ # ~/.termdeck/secrets.env should NEVER be committed — it lives outside the repo.
4
+ #
5
+ # These keys are referenced from ~/.termdeck/config.yaml via ${VAR} substitution,
6
+ # so you can edit yaml freely without accidentally leaking a secret.
7
+
8
+ # Supabase project that backs the RAG / Engram memory tables.
9
+ SUPABASE_URL=
10
+ SUPABASE_SERVICE_ROLE_KEY=
11
+
12
+ # OpenAI embeddings — only needed when rag.engramMode is `direct`.
13
+ OPENAI_API_KEY=
14
+
15
+ # Anthropic — powers the session-log summarizer (T2.5) and any future
16
+ # LLM-backed features that run server-side.
17
+ ANTHROPIC_API_KEY=
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@jhizzard/termdeck",
3
+ "version": "0.2.0",
4
+ "description": "Browser-based terminal multiplexer with metadata overlays, panel flashback memory recall, and AI-aware session management",
5
+ "bin": {
6
+ "termdeck": "./packages/cli/src/index.js"
7
+ },
8
+ "main": "packages/cli/src/index.js",
9
+ "files": [
10
+ "packages/cli/src/**",
11
+ "packages/server/src/**",
12
+ "packages/client/public/**",
13
+ "config/config.example.yaml",
14
+ "config/secrets.env.example",
15
+ "LICENSE",
16
+ "README.md"
17
+ ],
18
+ "workspaces": [
19
+ "packages/server",
20
+ "packages/client",
21
+ "packages/cli"
22
+ ],
23
+ "scripts": {
24
+ "dev": "node packages/server/src/index.js",
25
+ "server": "node packages/server/src/index.js",
26
+ "start": "NODE_ENV=production node packages/cli/src/index.js",
27
+ "install:app": "bash install.sh"
28
+ },
29
+ "dependencies": {
30
+ "express": "^4.18.2",
31
+ "ws": "^8.16.0",
32
+ "@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
33
+ "better-sqlite3": "^12.9.0",
34
+ "uuid": "^9.0.0",
35
+ "yaml": "^2.3.4",
36
+ "chalk": "^5.3.0",
37
+ "open": "^10.0.0"
38
+ },
39
+ "keywords": [
40
+ "terminal",
41
+ "multiplexer",
42
+ "xterm",
43
+ "pty",
44
+ "web-terminal",
45
+ "tmux-alternative",
46
+ "claude-code",
47
+ "memory",
48
+ "flashback",
49
+ "rag",
50
+ "devtools"
51
+ ],
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/jhizzard/termdeck.git"
55
+ },
56
+ "homepage": "https://github.com/jhizzard/termdeck#readme",
57
+ "bugs": {
58
+ "url": "https://github.com/jhizzard/termdeck/issues"
59
+ },
60
+ "author": "Joshua Izzard",
61
+ "license": "MIT",
62
+ "engines": {
63
+ "node": ">=18.0.0"
64
+ }
65
+ }
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+
3
+ // TermDeck CLI launcher
4
+ // Usage: termdeck [--port 3000] [--no-open]
5
+
6
+ const path = require('path');
7
+ const { execSync } = require('child_process');
8
+
9
+ // Parse CLI args
10
+ const args = process.argv.slice(2);
11
+ const flags = {};
12
+ for (let i = 0; i < args.length; i++) {
13
+ if (args[i] === '--port' && args[i + 1]) {
14
+ flags.port = parseInt(args[i + 1], 10);
15
+ i++;
16
+ } else if (args[i] === '--no-open') {
17
+ flags.noOpen = true;
18
+ } else if (args[i] === '--session-logs') {
19
+ flags.sessionLogs = true;
20
+ } else if (args[i] === '--help' || args[i] === '-h') {
21
+ console.log(`
22
+ TermDeck - Web-based terminal multiplexer
23
+
24
+ Usage:
25
+ termdeck Start with defaults (port 3000)
26
+ termdeck --port 8080 Start on custom port
27
+ termdeck --no-open Don't auto-open browser
28
+ termdeck --session-logs Write per-session markdown logs to ~/.termdeck/sessions/
29
+
30
+ Keyboard shortcuts (in browser):
31
+ Ctrl+Shift+N Focus prompt bar
32
+ Ctrl+Shift+1-6 Switch layout (1x1 → 4x2)
33
+ Ctrl+Shift+] / [ Next / previous terminal
34
+ Escape Exit focus/half mode
35
+
36
+ Config:
37
+ ~/.termdeck/config.yaml Server + project + RAG configuration
38
+ ~/.termdeck/termdeck.db Session history (SQLite)
39
+ `);
40
+ process.exit(0);
41
+ }
42
+ }
43
+
44
+ // Load and start server
45
+ const { createServer, loadConfig } = require(path.join(__dirname, '..', '..', 'server', 'src', 'index.js'));
46
+
47
+ // Flag-driven env vars must be set BEFORE loadConfig() so any module that
48
+ // reads process.env at require-time sees them.
49
+ if (flags.sessionLogs) {
50
+ process.env.TERMDECK_SESSION_LOGS = '1';
51
+ }
52
+
53
+ const config = loadConfig();
54
+ if (flags.port) config.port = flags.port;
55
+ if (flags.sessionLogs) {
56
+ config.sessionLogs = { ...(config.sessionLogs || {}), enabled: true };
57
+ console.log('[cli] session logs enabled — writing to ~/.termdeck/sessions/ on panel exit');
58
+ }
59
+
60
+ const { server } = createServer(config);
61
+ const port = config.port || 3000;
62
+ const host = config.host || '127.0.0.1';
63
+ const url = `http://${host}:${port}`;
64
+
65
+ server.listen(port, host, async () => {
66
+ console.log(`
67
+ ╔══════════════════════════════════════╗
68
+ ║ TermDeck v0.2.0 ║
69
+ ╠══════════════════════════════════════╣
70
+ ║ ${url.padEnd(34)} ║
71
+ ║ ║
72
+ ║ Ctrl+C to stop ║
73
+ ╚══════════════════════════════════════╝
74
+ `);
75
+
76
+ // Skip auto-open in Codespaces/CI (port forwarding handles it)
77
+ const isCodespaces = !!process.env.CODESPACES || !!process.env.GITHUB_CODESPACE_TOKEN;
78
+ const isCI = !!process.env.CI;
79
+
80
+ if (!flags.noOpen && !isCodespaces && !isCI) {
81
+ try {
82
+ const { platform } = require('os');
83
+ const cmd = platform() === 'darwin' ? 'open'
84
+ : platform() === 'win32' ? 'start'
85
+ : 'xdg-open';
86
+ execSync(`${cmd} ${url}`, { stdio: 'ignore' });
87
+ } catch (err) {
88
+ console.error('[cli] auto-open browser failed:', err.message);
89
+ console.log(` Open ${url} in your browser\n`);
90
+ }
91
+ } else if (isCodespaces) {
92
+ console.log(` Codespaces detected — use the Ports tab to open the browser\n`);
93
+ }
94
+ });
95
+
96
+ // Graceful shutdown
97
+ process.on('SIGINT', () => {
98
+ console.log('\n Shutting down TermDeck...');
99
+ server.close(() => process.exit(0));
100
+ setTimeout(() => process.exit(1), 3000);
101
+ });