@gbasin/agentboard 0.1.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 +21 -0
- package/README.md +154 -0
- package/bin/agentboard +63 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Gary Basin
|
|
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,154 @@
|
|
|
1
|
+
# Agentboard
|
|
2
|
+
|
|
3
|
+
Web UI for tmux, optimized for agent TUI's (`claude`, `codex`, etc).
|
|
4
|
+
|
|
5
|
+
Made this because I got sick of using tmux kb shortcuts on my phone, and using Blink.
|
|
6
|
+
|
|
7
|
+
Run your desktop/server, then connect from your phone or laptop over Tailscale/LAN. Shared workspace across devices.
|
|
8
|
+
|
|
9
|
+
- iOS Safari mobile experience with:
|
|
10
|
+
- Paste support (including images)
|
|
11
|
+
- Touch scrolling
|
|
12
|
+
- Virtual arrow keys / d-pad
|
|
13
|
+
- Quick keys toolbar (ctrl, esc, etc.)
|
|
14
|
+
- Out-of-the-box log tracking and matching for Claude, Codex, and Pi — auto-matches sessions to active tmux windows, with one-click restore for inactive sessions.
|
|
15
|
+
- Shows the last user prompt for each session, so you can remember what each agent is working on
|
|
16
|
+
- Pin agent TUI sessions to auto-resume them when the server restarts (useful if your machine reboots or tmux dies)
|
|
17
|
+
|
|
18
|
+
### Desktop
|
|
19
|
+
| Terminal | Sessions | Pinning |
|
|
20
|
+
| :---: | :---: | :---: |
|
|
21
|
+
| <img src="assets/desktop.png" alt="Terminal" height="400"/> | <img src="assets/sessions.png" alt="Sessions" height="400"/> | <img src="assets/pins.png" alt="Pinning" height="400"/> |
|
|
22
|
+
|
|
23
|
+
### Mobile
|
|
24
|
+
| Terminal | Controls |
|
|
25
|
+
| :---: | :---: |
|
|
26
|
+
| <img src="assets/mobile.jpeg" alt="Terminal" height="400"/> | <img src="assets/mobile-controls.jpeg" alt="Controls" height="400"/> |
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
- tmux (`brew install tmux` / `apt install tmux`)
|
|
31
|
+
- [Tailscale](https://tailscale.com/download) (recommended) or any network path to your machine
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
### npm
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g @gbasin/agentboard
|
|
39
|
+
agentboard
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or run directly:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx @gbasin/agentboard
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then open `http://localhost:4040` (or `http://<your-machine>:4040` from another device).
|
|
49
|
+
|
|
50
|
+
For persistent deployment on Linux, see [systemd/README.md](systemd/README.md).
|
|
51
|
+
|
|
52
|
+
### From source
|
|
53
|
+
|
|
54
|
+
Requires **Bun 1.3.6+** (see [Troubleshooting](#troubleshooting)).
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
bun install
|
|
58
|
+
bun run dev
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Open `http://<your-machine>:5173` (Vite dev server). In production, UI is served from the backend port (default 4040).
|
|
62
|
+
|
|
63
|
+
Production:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
bun run build
|
|
67
|
+
bun run start
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
For persistent deployment on Linux, see [systemd/README.md](systemd/README.md).
|
|
71
|
+
|
|
72
|
+
## Keyboard Shortcuts
|
|
73
|
+
|
|
74
|
+
| Action | Mac | Windows/Linux |
|
|
75
|
+
|--------|-----|---------------|
|
|
76
|
+
| Previous session | `Ctrl+Option+[` | `Ctrl+Shift+[` |
|
|
77
|
+
| Next session | `Ctrl+Option+]` | `Ctrl+Shift+]` |
|
|
78
|
+
| New session | `Ctrl+Option+N` | `Ctrl+Shift+N` |
|
|
79
|
+
| Kill session | `Ctrl+Option+X` | `Ctrl+Shift+X` |
|
|
80
|
+
|
|
81
|
+
## Environment
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
PORT=4040
|
|
85
|
+
HOSTNAME=0.0.0.0
|
|
86
|
+
TMUX_SESSION=agentboard
|
|
87
|
+
REFRESH_INTERVAL_MS=5000
|
|
88
|
+
DISCOVER_PREFIXES=work,external
|
|
89
|
+
PRUNE_WS_SESSIONS=true
|
|
90
|
+
TERMINAL_MODE=pty
|
|
91
|
+
TERMINAL_MONITOR_TARGETS=true
|
|
92
|
+
VITE_ALLOWED_HOSTS=nuc,myserver
|
|
93
|
+
AGENTBOARD_DB_PATH=~/.agentboard/agentboard.db
|
|
94
|
+
AGENTBOARD_INACTIVE_MAX_AGE_HOURS=24
|
|
95
|
+
AGENTBOARD_EXCLUDE_PROJECTS=<empty>,/workspace
|
|
96
|
+
AGENTBOARD_HOST=blade
|
|
97
|
+
AGENTBOARD_REMOTE_HOSTS=mba,carbon,worm
|
|
98
|
+
AGENTBOARD_REMOTE_POLL_MS=15000
|
|
99
|
+
AGENTBOARD_REMOTE_TIMEOUT_MS=4000
|
|
100
|
+
AGENTBOARD_REMOTE_STALE_MS=45000
|
|
101
|
+
AGENTBOARD_REMOTE_SSH_OPTS=-o BatchMode=yes -o ConnectTimeout=3
|
|
102
|
+
AGENTBOARD_REMOTE_ALLOW_CONTROL=false
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`HOSTNAME` controls which interfaces the server binds to (default `0.0.0.0` for network access; use `127.0.0.1` for local-only).
|
|
106
|
+
|
|
107
|
+
`DISCOVER_PREFIXES` lets you discover and control windows from other tmux sessions. If unset, all sessions except the managed one are discovered.
|
|
108
|
+
|
|
109
|
+
`PRUNE_WS_SESSIONS` removes orphaned `agentboard-ws-*` tmux sessions on startup (set to `false` to disable).
|
|
110
|
+
|
|
111
|
+
`TERMINAL_MODE` selects terminal I/O strategy: `pty` (default, grouped session) or `pipe-pane` (PTY-less, works in daemon/systemd/docker without `-t`).
|
|
112
|
+
|
|
113
|
+
`TERMINAL_MONITOR_TARGETS` (pipe-pane only) polls tmux to detect closed targets (set to `false` to disable).
|
|
114
|
+
|
|
115
|
+
`VITE_ALLOWED_HOSTS` allows access to the Vite dev server from other hostnames. Useful with Tailscale MagicDNS - add your machine name (e.g., `nuc`) to access the dev server at `http://nuc:5173` from other devices on your tailnet.
|
|
116
|
+
|
|
117
|
+
All persistent data is stored in `~/.agentboard/`: session database (`agentboard.db`) and logs (`agentboard.log`). Override paths with `AGENTBOARD_DB_PATH` and `LOG_FILE`.
|
|
118
|
+
|
|
119
|
+
`AGENTBOARD_INACTIVE_MAX_AGE_HOURS` limits inactive sessions shown in the UI to those with recent activity (default: 24 hours). Older sessions remain in the database but are not displayed or processed for orphan rematch.
|
|
120
|
+
|
|
121
|
+
`AGENTBOARD_EXCLUDE_PROJECTS` filters out sessions from specific project directories (comma-separated). Use `<empty>` to exclude sessions with no project path. Useful for hiding automated/spam sessions.
|
|
122
|
+
|
|
123
|
+
`AGENTBOARD_SKIP_MATCHING_PATTERNS` controls which orphan sessions skip expensive window matching (comma-separated). Defaults: `<codex-exec>` (headless Codex exec sessions), `/private/tmp/*`, `/private/var/folders/*`, `/var/folders/*`, `/tmp/*`. Patterns support trailing `*` for prefix matching. Set to empty string to disable skip matching entirely.
|
|
124
|
+
|
|
125
|
+
`AGENTBOARD_HOST` sets the host label for local sessions (default: `hostname`).
|
|
126
|
+
|
|
127
|
+
`AGENTBOARD_REMOTE_HOSTS` enables remote tmux polling over SSH. Provide a comma-separated list of hosts (e.g., `mba,carbon,worm`).
|
|
128
|
+
|
|
129
|
+
`AGENTBOARD_REMOTE_POLL_MS`, `AGENTBOARD_REMOTE_TIMEOUT_MS`, and `AGENTBOARD_REMOTE_STALE_MS` control remote poll cadence, SSH timeout, and stale host cutoff.
|
|
130
|
+
|
|
131
|
+
`AGENTBOARD_REMOTE_SSH_OPTS` appends extra SSH options (space-separated).
|
|
132
|
+
|
|
133
|
+
`AGENTBOARD_REMOTE_ALLOW_CONTROL` is reserved for future remote control support (read-only in MVP).
|
|
134
|
+
|
|
135
|
+
## Logging
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
LOG_LEVEL=info # debug | info | warn | error (default: info)
|
|
139
|
+
LOG_FILE=~/.agentboard/agentboard.log # default; set empty to disable file logging
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Console output is pretty-printed in development, JSON in production (`NODE_ENV=production`). File output is always JSON. Set `LOG_FILE=` (empty) to disable file logging.
|
|
143
|
+
|
|
144
|
+
## Troubleshooting
|
|
145
|
+
|
|
146
|
+
### "open terminal failed: not a terminal" errors
|
|
147
|
+
|
|
148
|
+
If you see infinite `open terminal failed: not a terminal` errors, you need to upgrade Bun:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
bun upgrade
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Root cause**: Bun versions prior to 1.3.6 had a bug where the `terminal` option in `Bun.spawn()` incorrectly set stdin to `/dev/null` instead of the PTY. Since `tmux attach` requires stdin to be a terminal, it fails immediately. This was fixed in Bun 1.3.6.
|
package/bin/agentboard
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
const PLATFORMS = {
|
|
10
|
+
"darwin-arm64": "@gbasin/agentboard-darwin-arm64",
|
|
11
|
+
"darwin-x64": "@gbasin/agentboard-darwin-x64",
|
|
12
|
+
"linux-x64": "@gbasin/agentboard-linux-x64",
|
|
13
|
+
"linux-arm64": "@gbasin/agentboard-linux-arm64",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function getBinaryPath() {
|
|
17
|
+
const platform = process.platform;
|
|
18
|
+
const supportedArch = { x64: "x64", arm64: "arm64" };
|
|
19
|
+
const arch = supportedArch[process.arch];
|
|
20
|
+
if (!arch) {
|
|
21
|
+
console.error(`Unsupported architecture: ${process.arch}`);
|
|
22
|
+
console.error(`Supported: ${Object.keys(supportedArch).join(", ")}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const key = `${platform}-${arch}`;
|
|
26
|
+
|
|
27
|
+
const pkg = PLATFORMS[key];
|
|
28
|
+
if (!pkg) {
|
|
29
|
+
console.error(`Unsupported platform: ${key}`);
|
|
30
|
+
console.error(`Supported: ${Object.keys(PLATFORMS).join(", ")}`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
return require.resolve(`${pkg}/bin/agentboard`);
|
|
36
|
+
} catch {
|
|
37
|
+
console.error(`Platform package not installed: ${pkg}`);
|
|
38
|
+
console.error(`Try: npm install ${pkg}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getPackageRoot(binaryPath) {
|
|
44
|
+
// Binary is at <pkg>/bin/agentboard, package root is <pkg>/
|
|
45
|
+
return dirname(dirname(binaryPath));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const binaryPath = getBinaryPath();
|
|
50
|
+
const packageRoot = getPackageRoot(binaryPath);
|
|
51
|
+
|
|
52
|
+
execFileSync(binaryPath, process.argv.slice(2), {
|
|
53
|
+
stdio: "inherit",
|
|
54
|
+
env: {
|
|
55
|
+
...process.env,
|
|
56
|
+
// Tell the server where to find dist/client relative to the platform package
|
|
57
|
+
AGENTBOARD_STATIC_DIR: join(packageRoot, "dist", "client"),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (e && e.status) process.exit(e.status);
|
|
62
|
+
throw e;
|
|
63
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gbasin/agentboard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A terminal dashboard for tracking agent coding sessions",
|
|
6
|
+
"author": "gbasin",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/gbasin/agentboard.git"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"agentboard": "./bin/agentboard"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin/**/*",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"bun": ">=1.3.6"
|
|
21
|
+
},
|
|
22
|
+
"optionalDependencies": {
|
|
23
|
+
"@gbasin/agentboard-darwin-arm64": "0.1.0",
|
|
24
|
+
"@gbasin/agentboard-darwin-x64": "0.1.0",
|
|
25
|
+
"@gbasin/agentboard-linux-x64": "0.1.0",
|
|
26
|
+
"@gbasin/agentboard-linux-arm64": "0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"dev": "concurrently -k \"bun run dev:server\" \"bun run dev:client\"",
|
|
30
|
+
"dev:server": "bun --watch src/server/index.ts",
|
|
31
|
+
"dev:client": "vite --host",
|
|
32
|
+
"build": "vite build",
|
|
33
|
+
"start": "bun src/server/index.ts",
|
|
34
|
+
"lint": "oxlint .",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"test": "bun scripts/test-runner.ts",
|
|
37
|
+
"test:coverage": "bun scripts/test-runner.ts --coverage --coverage-reporter=lcov --skip-isolated && bun run coverage:all",
|
|
38
|
+
"coverage:all": "bun scripts/coverage-all.ts",
|
|
39
|
+
"test:e2e": "playwright test",
|
|
40
|
+
"test:e2e:headed": "playwright test --headed",
|
|
41
|
+
"prepare": "git config core.hooksPath .githooks",
|
|
42
|
+
"release:patch": "bun scripts/release.ts patch",
|
|
43
|
+
"release:minor": "bun scripts/release.ts minor",
|
|
44
|
+
"release:major": "bun scripts/release.ts major"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@base-ui-components/react": "^1.0.0-rc.0",
|
|
48
|
+
"@dnd-kit/core": "^6.3.1",
|
|
49
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
50
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
51
|
+
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
|
52
|
+
"@untitledui-icons/react": "^1.0.3",
|
|
53
|
+
"@xterm/addon-clipboard": "^0.2.0",
|
|
54
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
55
|
+
"@xterm/addon-progress": "^0.1.0",
|
|
56
|
+
"@xterm/addon-search": "^0.15.0",
|
|
57
|
+
"@xterm/addon-serialize": "^0.14.0",
|
|
58
|
+
"@xterm/addon-web-links": "^0.12.0",
|
|
59
|
+
"@xterm/addon-webgl": "^0.18.0",
|
|
60
|
+
"@xterm/xterm": "^5.5.0",
|
|
61
|
+
"clsx": "^2.1.1",
|
|
62
|
+
"hono": "^4.6.10",
|
|
63
|
+
"motion": "^12.25.0",
|
|
64
|
+
"node-pty": "^1.1.0",
|
|
65
|
+
"pino": "^10.3.0",
|
|
66
|
+
"react": "^18.3.1",
|
|
67
|
+
"react-dom": "^18.3.1",
|
|
68
|
+
"tailwind-merge": "^3.4.0",
|
|
69
|
+
"zustand": "^5.0.0"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@playwright/test": "^1.55.0",
|
|
73
|
+
"pino-pretty": "^13.1.3",
|
|
74
|
+
"@types/node": "^22.10.2",
|
|
75
|
+
"@types/react": "^18.3.12",
|
|
76
|
+
"@types/react-dom": "^18.3.1",
|
|
77
|
+
"@types/react-test-renderer": "^19.1.0",
|
|
78
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
79
|
+
"autoprefixer": "^10.4.20",
|
|
80
|
+
"bun-types": "^1.3.5",
|
|
81
|
+
"concurrently": "^8.2.2",
|
|
82
|
+
"oxlint": "^1.38.0",
|
|
83
|
+
"postcss": "^8.4.49",
|
|
84
|
+
"react-test-renderer": "18.3.1",
|
|
85
|
+
"tailwindcss": "^3.4.14",
|
|
86
|
+
"typescript": "^5.7.2",
|
|
87
|
+
"vite": "^5.4.11"
|
|
88
|
+
}
|
|
89
|
+
}
|