opencode-dashboard 0.1.0 → 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/README.md +20 -1
- package/bin/cli.ts +16 -2
- package/dist/assets/{index-W-qyIr7d.js → index-DJanV0JQ.js} +2 -2
- package/dist/index.html +1 -1
- package/package.json +1 -1
- package/plugin/index.ts +245 -5
- package/server/index.ts +23 -3
- package/server/pid.ts +115 -5
- package/server/routes.ts +131 -0
- package/server/sse.ts +16 -0
- package/server/state.ts +518 -1
- package/shared/types.ts +17 -7
- package/shared/version.ts +46 -0
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ npx opencode-dashboard start
|
|
|
41
41
|
|
|
42
42
|
The dashboard will be available at `http://localhost:3333`.
|
|
43
43
|
|
|
44
|
+
After the first activation, the dashboard **auto-starts on subsequent OpenCode sessions** — you don't need to run `/dashboard-start` again. This works across terminals: if you open a second OpenCode session while the dashboard is already running, it connects automatically.
|
|
45
|
+
|
|
44
46
|
### Check Status
|
|
45
47
|
|
|
46
48
|
```
|
|
@@ -65,6 +67,8 @@ Or via CLI:
|
|
|
65
67
|
npx opencode-dashboard stop
|
|
66
68
|
```
|
|
67
69
|
|
|
70
|
+
This also **disables auto-start** — the dashboard will stay dormant on future sessions until you explicitly run `/dashboard-start` again.
|
|
71
|
+
|
|
68
72
|
### Custom Port
|
|
69
73
|
|
|
70
74
|
```bash
|
|
@@ -90,7 +94,7 @@ OpenCode Plugin (plugin/index.ts)
|
|
|
90
94
|
```
|
|
91
95
|
|
|
92
96
|
1. **Plugin** -- An OpenCode plugin that hooks into agent lifecycle events, discovers configured agents, tracks bead state via `bd list --json`, and pushes structured events to the server. Registers custom tools (`dashboard_start`, `dashboard_stop`, `dashboard_status`, `dashboard_open`) for controlling the dashboard from within OpenCode.
|
|
93
|
-
2. **Server** -- A Bun HTTP server that aggregates state from connected plugins, persists it to disk, serves the dashboard frontend, and broadcasts updates to browser clients via Server-Sent Events (SSE).
|
|
97
|
+
2. **Server** -- A Bun HTTP server that aggregates state from connected plugins, persists it to disk, serves the dashboard frontend, and broadcasts updates to browser clients via Server-Sent Events (SSE). The server automatically shuts down after 5 minutes of inactivity (no connected plugins or browser clients) to avoid leaving orphaned processes. Multiple OpenCode sessions share a single server instance — it only shuts down when all sessions have disconnected.
|
|
94
98
|
3. **Dashboard** -- A React SPA that renders a dynamic Kanban board with real-time updates, animated card transitions, and connection resilience.
|
|
95
99
|
|
|
96
100
|
### Kanban Columns
|
|
@@ -220,6 +224,7 @@ bun test
|
|
|
220
224
|
| `server/state.test.ts` | Server state manager (event processing, persistence) |
|
|
221
225
|
| `server/routes.test.ts` | HTTP route handlers (register, event, heartbeat) |
|
|
222
226
|
| `server/sse.test.ts` | SSE client management and broadcasting |
|
|
227
|
+
| `server/pid.test.ts` | PID file and autostart marker management |
|
|
223
228
|
| `server/diffBeadState.test.ts` | Bead snapshot diffing algorithm |
|
|
224
229
|
|
|
225
230
|
### Building
|
|
@@ -235,6 +240,7 @@ bun run build:check # Run TypeScript type checking
|
|
|
235
240
|
|----------|---------|-------------|
|
|
236
241
|
| `DASHBOARD_PORT` | `3333` | Port for the dashboard server |
|
|
237
242
|
| `DASHBOARD_DEBUG` | (unset) | Set to `1` to enable verbose plugin logging to stderr |
|
|
243
|
+
| `DASHBOARD_IDLE_TIMEOUT_MS` | `300000` (5 min) | Idle auto-shutdown timeout in milliseconds. Set to `0` to disable |
|
|
238
244
|
|
|
239
245
|
## Project Structure
|
|
240
246
|
|
|
@@ -324,6 +330,19 @@ The server saves state to `server/.dashboard-state.json`. Delete this file to st
|
|
|
324
330
|
rm server/.dashboard-state.json
|
|
325
331
|
```
|
|
326
332
|
|
|
333
|
+
### Dashboard keeps auto-starting (or won't auto-start)
|
|
334
|
+
|
|
335
|
+
The plugin stores an autostart marker at `~/.cache/opencode/opencode-dashboard.autostart`. To reset auto-start behavior:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# Disable auto-start
|
|
339
|
+
rm ~/.cache/opencode/opencode-dashboard.autostart
|
|
340
|
+
|
|
341
|
+
# Or just run /dashboard-stop — it clears the marker for you
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
If the dashboard *should* auto-start but isn't, run `/dashboard-start` once to re-create the marker.
|
|
345
|
+
|
|
327
346
|
## License
|
|
328
347
|
|
|
329
348
|
[MIT](LICENSE)
|
package/bin/cli.ts
CHANGED
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
import { join } from "path";
|
|
21
21
|
import { readdir, copyFile, mkdir, stat } from "fs/promises";
|
|
22
22
|
import { createInterface } from "readline";
|
|
23
|
-
import { readPid, removePid, isServerRunning } from "../server/pid";
|
|
23
|
+
import { readPid, removePid, isServerRunning, openLogFile, getLogFilePath } from "../server/pid";
|
|
24
|
+
import { closeSync } from "fs";
|
|
24
25
|
|
|
25
26
|
// ─── Constants ─────────────────────────────────────────────────
|
|
26
27
|
|
|
@@ -110,16 +111,27 @@ async function cmdStart(args: string[]): Promise<void> {
|
|
|
110
111
|
// Use Bun.which to find bun reliably (process.execPath may not always be bun)
|
|
111
112
|
const bunPath = Bun.which("bun") ?? process.execPath;
|
|
112
113
|
|
|
114
|
+
let logFd: number | undefined;
|
|
115
|
+
try {
|
|
116
|
+
logFd = openLogFile();
|
|
117
|
+
} catch {
|
|
118
|
+
// If log file can't be opened, fall back to ignore
|
|
119
|
+
}
|
|
120
|
+
|
|
113
121
|
try {
|
|
114
122
|
const proc = Bun.spawn([bunPath, "run", SERVER_ENTRY], {
|
|
115
123
|
detached: true,
|
|
116
|
-
stdio: ["ignore", "ignore", "ignore"],
|
|
124
|
+
stdio: ["ignore", logFd ?? "ignore", logFd ?? "ignore"],
|
|
117
125
|
env: { ...process.env, DASHBOARD_PORT: String(port) },
|
|
118
126
|
});
|
|
119
127
|
proc.unref();
|
|
120
128
|
} catch (err: any) {
|
|
121
129
|
console.error(`Failed to start server: ${err?.message ?? err}`);
|
|
122
130
|
process.exit(1);
|
|
131
|
+
} finally {
|
|
132
|
+
if (logFd !== undefined) {
|
|
133
|
+
try { closeSync(logFd); } catch {}
|
|
134
|
+
}
|
|
123
135
|
}
|
|
124
136
|
|
|
125
137
|
// Poll for readiness
|
|
@@ -128,12 +140,14 @@ async function cmdStart(args: string[]): Promise<void> {
|
|
|
128
140
|
await Bun.sleep(SPAWN_POLL_INTERVAL_MS);
|
|
129
141
|
if (await checkHealth(port)) {
|
|
130
142
|
console.log(`Dashboard running at http://localhost:${port}`);
|
|
143
|
+
console.log(` Logs: ${getLogFilePath()}`);
|
|
131
144
|
return;
|
|
132
145
|
}
|
|
133
146
|
}
|
|
134
147
|
|
|
135
148
|
console.error(`Server failed to start within ${SPAWN_TIMEOUT_MS / 1000}s.`);
|
|
136
149
|
console.error(`Check if port ${port} is already in use.`);
|
|
150
|
+
console.error(` Logs: ${getLogFilePath()}`);
|
|
137
151
|
process.exit(1);
|
|
138
152
|
}
|
|
139
153
|
|