opencode-dashboard-server 0.1.0__tar.gz → 0.2.0__tar.gz

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.
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: opencode-dashboard-server
3
+ Version: 0.2.0
4
+ Summary: FastAPI aggregator over opencode's SQLite storage
5
+ Project-URL: Homepage, https://github.com/GCS-ZHN/opencode-dashboard
6
+ Project-URL: Repository, https://github.com/GCS-ZHN/opencode-dashboard
7
+ Project-URL: Issues, https://github.com/GCS-ZHN/opencode-dashboard/issues
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: fastapi<1,>=0.115
11
+ Requires-Dist: uvicorn<1,>=0.30
12
+
13
+ # opencode-dashboard-server
14
+
15
+ FastAPI aggregation backend for the [opencode-dashboard](https://github.com/GCS-ZHN/opencode-dashboard)
16
+ project. Reads opencode's local SQLite storage via the `opencode db` CLI and exposes a JSON + SSE
17
+ API for the dashboard front end.
18
+
19
+ ## Install (PyPI)
20
+
21
+ ```bash
22
+ pip install opencode-dashboard-server
23
+ ```
24
+
25
+ Requires:
26
+
27
+ - **Python ≥ 3.10**
28
+ - **`opencode` CLI** on the same host — the server shells out to `opencode db "<SQL>"` and never
29
+ opens the SQLite file directly (it's WAL-mode and actively written while opencode runs).
30
+
31
+ ## Quick start
32
+
33
+ Run one aggregator per opencode host:
34
+
35
+ ```bash
36
+ uvicorn app:app --port 8791
37
+ ```
38
+
39
+ Run on more hosts with different ports (`8792`, `8793`, …) and list each in the front end's
40
+ `dashboard.yaml`. Environment switches:
41
+
42
+ - `DASHBOARD_CORS_ORIGINS` — comma-separated CORS allow-list (defaults to the loopback dev origins `localhost/127.0.0.1:5173` and `:4173`; tighten or widen for your deployment).
43
+ - `DASHBOARD_POLL_SECONDS` — SSE poll interval in seconds (default `5`).
44
+ - `OPENCODE_BIN` — path to the `opencode` binary if it's not on `PATH`.
45
+
46
+ ## API
47
+
48
+ - `GET /health` — liveness
49
+ - `GET /overview` — whole-host aggregate (tokens by type + cost, session counts, `updatedAt`)
50
+ - `GET /projects` — per-project rollups
51
+ - `GET /projects/{id}` — one project's sessions (parent/child tree)
52
+ - `GET /sessions/{id}` — per-model breakdown for one session (handles mid-conversation model switches)
53
+ - `GET /stream` — SSE: `updated` events when the DB changes (polled ~5s)
54
+
55
+ JSON is camelCase, timestamps are epoch-ms. Full contract in the repo's `API.md`.
56
+
57
+ ## From source (development)
58
+
59
+ ```bash
60
+ git clone https://github.com/GCS-ZHN/opencode-dashboard
61
+ cd opencode-dashboard/server
62
+ uv sync # install deps (fastapi, uvicorn) + dev (pytest, httpx)
63
+ uv run pytest # run tests
64
+ uvx ruff check . # lint
65
+ ```
@@ -0,0 +1,53 @@
1
+ # opencode-dashboard-server
2
+
3
+ FastAPI aggregation backend for the [opencode-dashboard](https://github.com/GCS-ZHN/opencode-dashboard)
4
+ project. Reads opencode's local SQLite storage via the `opencode db` CLI and exposes a JSON + SSE
5
+ API for the dashboard front end.
6
+
7
+ ## Install (PyPI)
8
+
9
+ ```bash
10
+ pip install opencode-dashboard-server
11
+ ```
12
+
13
+ Requires:
14
+
15
+ - **Python ≥ 3.10**
16
+ - **`opencode` CLI** on the same host — the server shells out to `opencode db "<SQL>"` and never
17
+ opens the SQLite file directly (it's WAL-mode and actively written while opencode runs).
18
+
19
+ ## Quick start
20
+
21
+ Run one aggregator per opencode host:
22
+
23
+ ```bash
24
+ uvicorn app:app --port 8791
25
+ ```
26
+
27
+ Run on more hosts with different ports (`8792`, `8793`, …) and list each in the front end's
28
+ `dashboard.yaml`. Environment switches:
29
+
30
+ - `DASHBOARD_CORS_ORIGINS` — comma-separated CORS allow-list (defaults to the loopback dev origins `localhost/127.0.0.1:5173` and `:4173`; tighten or widen for your deployment).
31
+ - `DASHBOARD_POLL_SECONDS` — SSE poll interval in seconds (default `5`).
32
+ - `OPENCODE_BIN` — path to the `opencode` binary if it's not on `PATH`.
33
+
34
+ ## API
35
+
36
+ - `GET /health` — liveness
37
+ - `GET /overview` — whole-host aggregate (tokens by type + cost, session counts, `updatedAt`)
38
+ - `GET /projects` — per-project rollups
39
+ - `GET /projects/{id}` — one project's sessions (parent/child tree)
40
+ - `GET /sessions/{id}` — per-model breakdown for one session (handles mid-conversation model switches)
41
+ - `GET /stream` — SSE: `updated` events when the DB changes (polled ~5s)
42
+
43
+ JSON is camelCase, timestamps are epoch-ms. Full contract in the repo's `API.md`.
44
+
45
+ ## From source (development)
46
+
47
+ ```bash
48
+ git clone https://github.com/GCS-ZHN/opencode-dashboard
49
+ cd opencode-dashboard/server
50
+ uv sync # install deps (fastapi, uvicorn) + dev (pytest, httpx)
51
+ uv run pytest # run tests
52
+ uvx ruff check . # lint
53
+ ```
@@ -6,6 +6,7 @@ Run: uv run uvicorn app:app --reload
6
6
  import asyncio
7
7
  import json
8
8
  import logging
9
+ import os
9
10
  import socket
10
11
  import subprocess
11
12
  from functools import lru_cache
@@ -19,6 +20,20 @@ from db import CliRunner
19
20
 
20
21
  logger = logging.getLogger("dashboard")
21
22
 
23
+ # Comma-separated CORS allow-list; defaults to the loopback dev origins. Tight
24
+ # by default so a random webpage can't exfiltrate local project/session data.
25
+ def cors_origins() -> list[str]:
26
+ env = os.environ.get("DASHBOARD_CORS_ORIGINS", "").strip()
27
+ if env:
28
+ return [o.strip() for o in env.split(",") if o.strip()]
29
+ return [
30
+ "http://localhost:5173", "http://127.0.0.1:5173",
31
+ "http://localhost:4173", "http://127.0.0.1:4173",
32
+ ]
33
+
34
+
35
+ POLL_SECONDS = float(os.environ.get("DASHBOARD_POLL_SECONDS", "5"))
36
+
22
37
 
23
38
  @lru_cache(maxsize=1)
24
39
  def opencode_version() -> str:
@@ -37,10 +52,7 @@ def create_app(runner=None) -> FastAPI:
37
52
  # local project/session data from the browser (the client runs from Vite).
38
53
  app.add_middleware(
39
54
  CORSMiddleware,
40
- allow_origins=[
41
- "http://localhost:5173", "http://127.0.0.1:5173",
42
- "http://localhost:4173", "http://127.0.0.1:4173",
43
- ],
55
+ allow_origins=cors_origins(),
44
56
  allow_methods=["*"],
45
57
  allow_headers=["*"],
46
58
  )
@@ -116,7 +128,7 @@ def create_app(runner=None) -> FastAPI:
116
128
  except Exception:
117
129
  logger.exception("stream poll failed")
118
130
  try:
119
- await asyncio.wait_for(stop.wait(), 5)
131
+ await asyncio.wait_for(stop.wait(), POLL_SECONDS)
120
132
  except asyncio.TimeoutError:
121
133
  pass
122
134
 
@@ -11,8 +11,12 @@ Two interchangeable runners over the same SQL surface:
11
11
  """
12
12
 
13
13
  import json
14
+ import os
14
15
  import subprocess
15
16
 
17
+ # opencode CLI binary; override for a non-PATH install (e.g. a brew cellar path).
18
+ OPENCODE_BIN = os.environ.get("OPENCODE_BIN", "opencode")
19
+
16
20
 
17
21
  def _inline(sql: str, params: tuple) -> str:
18
22
  """Inline bound params into SQL as safely-quoted literals (CliRunner has no
@@ -29,8 +33,8 @@ def _inline(sql: str, params: tuple) -> str:
29
33
 
30
34
 
31
35
  class CliRunner:
32
- def __init__(self, executable: str = "opencode"):
33
- self._cmd = [executable, "db"]
36
+ def __init__(self, executable: str | None = None):
37
+ self._cmd = [executable or OPENCODE_BIN, "db"]
34
38
 
35
39
  def query(self, sql: str, params: tuple = ()) -> list[dict]:
36
40
  raw = subprocess.run(
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: opencode-dashboard-server
3
+ Version: 0.2.0
4
+ Summary: FastAPI aggregator over opencode's SQLite storage
5
+ Project-URL: Homepage, https://github.com/GCS-ZHN/opencode-dashboard
6
+ Project-URL: Repository, https://github.com/GCS-ZHN/opencode-dashboard
7
+ Project-URL: Issues, https://github.com/GCS-ZHN/opencode-dashboard/issues
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: fastapi<1,>=0.115
11
+ Requires-Dist: uvicorn<1,>=0.30
12
+
13
+ # opencode-dashboard-server
14
+
15
+ FastAPI aggregation backend for the [opencode-dashboard](https://github.com/GCS-ZHN/opencode-dashboard)
16
+ project. Reads opencode's local SQLite storage via the `opencode db` CLI and exposes a JSON + SSE
17
+ API for the dashboard front end.
18
+
19
+ ## Install (PyPI)
20
+
21
+ ```bash
22
+ pip install opencode-dashboard-server
23
+ ```
24
+
25
+ Requires:
26
+
27
+ - **Python ≥ 3.10**
28
+ - **`opencode` CLI** on the same host — the server shells out to `opencode db "<SQL>"` and never
29
+ opens the SQLite file directly (it's WAL-mode and actively written while opencode runs).
30
+
31
+ ## Quick start
32
+
33
+ Run one aggregator per opencode host:
34
+
35
+ ```bash
36
+ uvicorn app:app --port 8791
37
+ ```
38
+
39
+ Run on more hosts with different ports (`8792`, `8793`, …) and list each in the front end's
40
+ `dashboard.yaml`. Environment switches:
41
+
42
+ - `DASHBOARD_CORS_ORIGINS` — comma-separated CORS allow-list (defaults to the loopback dev origins `localhost/127.0.0.1:5173` and `:4173`; tighten or widen for your deployment).
43
+ - `DASHBOARD_POLL_SECONDS` — SSE poll interval in seconds (default `5`).
44
+ - `OPENCODE_BIN` — path to the `opencode` binary if it's not on `PATH`.
45
+
46
+ ## API
47
+
48
+ - `GET /health` — liveness
49
+ - `GET /overview` — whole-host aggregate (tokens by type + cost, session counts, `updatedAt`)
50
+ - `GET /projects` — per-project rollups
51
+ - `GET /projects/{id}` — one project's sessions (parent/child tree)
52
+ - `GET /sessions/{id}` — per-model breakdown for one session (handles mid-conversation model switches)
53
+ - `GET /stream` — SSE: `updated` events when the DB changes (polled ~5s)
54
+
55
+ JSON is camelCase, timestamps are epoch-ms. Full contract in the repo's `API.md`.
56
+
57
+ ## From source (development)
58
+
59
+ ```bash
60
+ git clone https://github.com/GCS-ZHN/opencode-dashboard
61
+ cd opencode-dashboard/server
62
+ uv sync # install deps (fastapi, uvicorn) + dev (pytest, httpx)
63
+ uv run pytest # run tests
64
+ uvx ruff check . # lint
65
+ ```
@@ -4,8 +4,9 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opencode-dashboard-server"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "FastAPI aggregator over opencode's SQLite storage"
9
+ readme = "README.md"
9
10
  requires-python = ">=3.10"
10
11
  dependencies = [
11
12
  "fastapi>=0.115,<1",
@@ -14,6 +15,8 @@ dependencies = [
14
15
 
15
16
  [project.urls]
16
17
  Homepage = "https://github.com/GCS-ZHN/opencode-dashboard"
18
+ Repository = "https://github.com/GCS-ZHN/opencode-dashboard"
19
+ Issues = "https://github.com/GCS-ZHN/opencode-dashboard/issues"
17
20
 
18
21
  [tool.setuptools]
19
22
  py-modules = ["app", "aggregate", "db"]
@@ -1,8 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: opencode-dashboard-server
3
- Version: 0.1.0
4
- Summary: FastAPI aggregator over opencode's SQLite storage
5
- Project-URL: Homepage, https://github.com/GCS-ZHN/opencode-dashboard
6
- Requires-Python: >=3.10
7
- Requires-Dist: fastapi<1,>=0.115
8
- Requires-Dist: uvicorn<1,>=0.30
@@ -1,8 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: opencode-dashboard-server
3
- Version: 0.1.0
4
- Summary: FastAPI aggregator over opencode's SQLite storage
5
- Project-URL: Homepage, https://github.com/GCS-ZHN/opencode-dashboard
6
- Requires-Python: >=3.10
7
- Requires-Dist: fastapi<1,>=0.115
8
- Requires-Dist: uvicorn<1,>=0.30