Compare commits

...
50 Commits
Author SHA1 Message Date
mytheclipsebotreview[bot] e5fb73f61e Auto-merge PR #27
chore(deps-dev): bump @biomejs/biome from 2.5.8 to 2.5.9 in the biome group
2026-08-21 00:11:10 +00:00
dependabot[bot] 665de9e0fc chore(deps-dev): bump @biomejs/biome in the biome group
Bumps the biome group with 1 update: [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome).


Updates `@biomejs/biome` from 2.5.8 to 2.5.9
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.9/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: biome
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-21 00:08:00 +00:00
mytheclipsebotreview[bot] 4a6b498879 Auto-merge PR #26
chore(deps): update react-resizable-panels requirement from ^4.12.2 to ^4.12.3
2026-08-20 00:11:30 +00:00
dependabot[bot] 7db6cc32b6 chore(deps): update react-resizable-panels requirement
Updates the requirements on [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) to permit the latest version.
- [Release notes](https://github.com/bvaughn/react-resizable-panels/releases)
- [Changelog](https://github.com/bvaughn/react-resizable-panels/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bvaughn/react-resizable-panels/compare/4.12.2...4.12.3)

---
updated-dependencies:
- dependency-name: react-resizable-panels
  dependency-version: 4.12.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-20 00:09:18 +00:00
mytheclipsebotreview[bot] e9900ef20c Auto-merge PR #25
chore(deps): update shadcn requirement from ^4.16.2 to ^4.18.0
2026-08-17 00:18:11 +00:00
mytheclipsebotreview[bot] ed9fa16b57 Auto-merge PR #24
chore(deps-dev): bump @biomejs/biome from 2.5.7 to 2.5.8 in the biome group
2026-08-17 00:18:03 +00:00
mytheclipsebotreview[bot] 1640230c66 Auto-merge PR #23
chore(deps): bump next from 16.3.0 to 16.3.1 in the nextjs group
2026-08-17 00:17:52 +00:00
dependabot[bot] 29ad253a61 chore(deps): update shadcn requirement from ^4.16.2 to ^4.18.0
Updates the requirements on [shadcn](https://github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn) to permit the latest version.
- [Release notes](https://github.com/shadcn-ui/ui/releases)
- [Changelog](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/CHANGELOG.md)
- [Commits](https://github.com/shadcn-ui/ui/commits/shadcn@4.18.0/packages/shadcn)

---
updated-dependencies:
- dependency-name: shadcn
  dependency-version: 4.18.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-17 00:15:55 +00:00
dependabot[bot] 5c37f3f611 chore(deps-dev): bump @biomejs/biome in the biome group
Bumps the biome group with 1 update: [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome).


Updates `@biomejs/biome` from 2.5.7 to 2.5.8
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.8/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: biome
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-17 00:15:11 +00:00
dependabot[bot] fbaead91a9 chore(deps): bump next from 16.3.0 to 16.3.1 in the nextjs group
Bumps the nextjs group with 1 update: [next](https://github.com/vercel/next.js).


Updates `next` from 16.3.0 to 16.3.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/compare/v16.3.0...v16.3.1)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nextjs
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-17 00:14:59 +00:00
mytheclipsebotreview[bot] c891439857 Auto-merge PR #22
chore(deps): update framer-motion requirement from ^13.0.0 to ^13.1.0
2026-08-14 00:14:05 +00:00
dependabot[bot] f77493a04b chore(deps): update framer-motion requirement from ^13.0.0 to ^13.1.0
Updates the requirements on [framer-motion](https://github.com/motiondivision/motion) to permit the latest version.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v13.0.0...v13.1.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 13.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-14 00:10:03 +00:00
mytheclipsebotreview[bot] 137eecdc1d Auto-merge PR #21
chore(deps): update sonner requirement from ^2.0.7 to ^2.0.8
2026-08-13 00:13:15 +00:00
mytheclipsebotreview[bot] bfbfc175ca Auto-merge PR #20
chore(deps): update lucide-react requirement from ^1.30.0 to ^1.31.0
2026-08-13 00:13:07 +00:00
dependabot[bot] 0fd992bb21 chore(deps): update sonner requirement from ^2.0.7 to ^2.0.8
Updates the requirements on [sonner](https://github.com/emilkowalski/sonner) to permit the latest version.
- [Release notes](https://github.com/emilkowalski/sonner/releases)
- [Commits](https://github.com/emilkowalski/sonner/compare/v2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: sonner
  dependency-version: 2.0.8
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-13 00:06:54 +00:00
dependabot[bot] c5412fa89b chore(deps): update lucide-react requirement from ^1.30.0 to ^1.31.0
Updates the requirements on [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) to permit the latest version.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.31.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.31.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-13 00:06:44 +00:00
mytheclipsebotreview[bot] b30e6936b1 Auto-merge PR #19
chore(deps): bump lucide-react from 1.31.0 to 1.30.0
2026-08-11 00:12:27 +00:00
dependabot[bot] 293863b5b0 chore(deps): bump lucide-react from 1.31.0 to 1.30.0
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 1.31.0 to 1.30.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.30.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.30.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-11 00:08:37 +00:00
mytheclipsebotreview[bot] 9ea002a7a1 Auto-merge PR #17
chore(deps): bump lucide-react from 1.31.0 to 1.29.0
2026-08-10 00:24:13 +00:00
mytheclipsebotreview[bot] e67db071bb Auto-merge PR #18
chore(deps): update @base-ui/react requirement from ^1.6.0 to ^1.7.0
2026-08-10 00:23:58 +00:00
dependabot[bot] 948bbf3de5 chore(deps): bump lucide-react from 1.31.0 to 1.29.0
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 1.31.0 to 1.29.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.29.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 00:20:24 +00:00
dependabot[bot] d6ef68f450 chore(deps): update @base-ui/react requirement from ^1.6.0 to ^1.7.0
Updates the requirements on [@base-ui/react](https://github.com/mui/base-ui/tree/HEAD/packages/react) to permit the latest version.
- [Release notes](https://github.com/mui/base-ui/releases)
- [Changelog](https://github.com/mui/base-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/base-ui/commits/v1.7.0/packages/react)

---
updated-dependencies:
- dependency-name: "@base-ui/react"
  dependency-version: 1.7.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 00:20:15 +00:00
mytheclipsebotreview[bot] c0875de75b Auto-merge PR #15
chore(deps): update shadcn requirement from ^4.16.1 to ^4.16.2
2026-08-10 00:18:24 +00:00
mytheclipsebotreview[bot] 17a785c9d2 Auto-merge PR #16
chore(deps): bump framer-motion from 12.43.0 to 13.0.0
2026-08-10 00:18:15 +00:00
mytheclipsebotreview[bot] 915d848294 Auto-merge PR #14
chore(deps-dev): bump @biomejs/biome from 2.5.6 to 2.5.7 in the biome group
2026-08-10 00:18:08 +00:00
mytheclipsebotreview[bot] a5bf846e52 Auto-merge PR #13
chore(deps): bump @shadcn/react from 0.2.1 to 0.3.0 in the shadcn group
2026-08-10 00:18:00 +00:00
dependabot[bot] 15c82ea3b7 chore(deps): bump framer-motion from 12.43.0 to 13.0.0
Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.43.0 to 13.0.0.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.43.0...v13.0.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 00:16:38 +00:00
dependabot[bot] f8b98d9b30 chore(deps): update shadcn requirement from ^4.16.1 to ^4.16.2
Updates the requirements on [shadcn](https://github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn) to permit the latest version.
- [Release notes](https://github.com/shadcn-ui/ui/releases)
- [Changelog](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/CHANGELOG.md)
- [Commits](https://github.com/shadcn-ui/ui/commits/shadcn@4.16.2/packages/shadcn)

---
updated-dependencies:
- dependency-name: shadcn
  dependency-version: 4.16.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 00:16:27 +00:00
dependabot[bot] 68a4f1e36e chore(deps-dev): bump @biomejs/biome in the biome group
Bumps the biome group with 1 update: [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome).


Updates `@biomejs/biome` from 2.5.6 to 2.5.7
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.7/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: biome
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 00:15:52 +00:00
dependabot[bot] 78d730fad9 chore(deps): bump @shadcn/react from 0.2.1 to 0.3.0 in the shadcn group
Bumps the shadcn group with 1 update: [@shadcn/react](https://github.com/shadcn-ui/ui/tree/HEAD/packages/react).


Updates `@shadcn/react` from 0.2.1 to 0.3.0
- [Release notes](https://github.com/shadcn-ui/ui/releases)
- [Changelog](https://github.com/shadcn-ui/ui/blob/main/packages/react/CHANGELOG.md)
- [Commits](https://github.com/shadcn-ui/ui/commits/@shadcn/react@0.3.0/packages/react)

---
updated-dependencies:
- dependency-name: "@shadcn/react"
  dependency-version: 0.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: shadcn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 00:15:43 +00:00
mytheclipsebotreview[bot] eb80d4a0fd Auto-merge PR #12
chore(deps): bump next from 16.2.12 to 16.3.0 in the nextjs group
2026-08-07 00:10:26 +00:00
dependabot[bot] f35dd25819 chore(deps): bump next from 16.2.12 to 16.3.0 in the nextjs group
Bumps the nextjs group with 1 update: [next](https://github.com/vercel/next.js).


Updates `next` from 16.2.12 to 16.3.0
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/compare/v16.2.12...v16.3.0)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nextjs
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-07 00:07:58 +00:00
asepharyana 55310768a5 Merge pull request #11 from asepharyana/dependabot/npm_and_yarn/shadcn-tw-4.16.1
chore(deps): update shadcn requirement from ^4.16.0 to ^4.16.1
2026-08-04 09:39:06 +07:00
dependabot[bot] 4b4c0123e3 chore(deps): update shadcn requirement from ^4.16.0 to ^4.16.1
Updates the requirements on [shadcn](https://github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn) to permit the latest version.
- [Release notes](https://github.com/shadcn-ui/ui/releases)
- [Changelog](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/CHANGELOG.md)
- [Commits](https://github.com/shadcn-ui/ui/commits/shadcn@4.16.1/packages/shadcn)

---
updated-dependencies:
- dependency-name: shadcn
  dependency-version: 4.16.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-04 00:06:49 +00:00
asepharyana ad6b1847c5 Merge pull request #10 from asepharyana/dependabot/npm_and_yarn/lucide-react-tw-1.28.0
chore(deps): update lucide-react requirement from ^1.27.0 to ^1.28.0
2026-08-03 16:22:03 +07:00
asepharyana a90d0c4333 fix(dashboard): real error rate from llm_api_errors_total
- errors now = rate(llm_api_errors_total) instead of network TX bytes
- rps = rate(llm_api_requests_total) + rate(http_server_request_count_total)
- Latency card → Load Average (was misleading: showed node load as 'ms')
- Overview 'Errors' StatBox was hardcoded 0 → real llm err/s
- rename hasTraffik → hasTraffic (Traefik removed 2026-08-02)
2026-08-03 13:06:27 +07:00
asepharyana 62966fd7cf feat(dashboard): LLM Inference card with live llm-api metrics
- /api/dashboard now queries llm-api Prometheus metrics: req/s, tok/s, gen tok/s, uptime, sparklines
- new LLM Inference card shows gen throughput + uptime badge + traffic sparkline
- fmtUptime helper (human-readable duration)
2026-08-03 12:45:19 +07:00
dependabot[bot] 82f8b9a457 chore(deps): update lucide-react requirement from ^1.27.0 to ^1.28.0
Updates the requirements on [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) to permit the latest version.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.28.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.28.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-03 00:14:02 +00:00
asepharyana 6829c7efe2 fix(infra): disable Next image disk cache for read-only Nix store
Next.js image optimizer mkdirs <distDir>/cache/images on first
optimized-image request. In the Nix store that path is read-only, so
every image request throws EACCES unhandledRejection. images.maximumDiskCacheSize=0
plus experimental.isrFlushToDisk=false keep the optimizer in-memory only.
2026-08-03 04:05:03 +07:00
asepharyana f35edb00d7 fix(dashboard): replace Docker/Jaeger with systemd + local Prometheus
- systemd list-units instead of /var/run/docker.sock (Docker removed)
- PROMETHEUS http://127.0.0.1:9090 (was http://prometheus:9090 Docker DNS)
- remove Jaeger trace fetch (Jaeger decommissioned)
- monitored units: caddy, gmw, 9router, lidm, teleuploader, zeavis, etc.
- web links from monitored units with Caddy sites
2026-08-02 20:54:47 +07:00
mytheclipsebotreview[bot] b007ced615 Auto-merge PR #9
Notify Parent Repo / dispatch (push) Canceled after 0s
chore(deps): update framer-motion requirement from ^12.42.2 to ^12.43.0
2026-07-29 00:11:42 +00:00
mytheclipsebotreview[bot] 5370fd4795 Auto-merge PR #8
chore(deps-dev): bump @biomejs/biome from 2.5.5 to 2.5.6 in the biome group
2026-07-29 00:09:45 +00:00
dependabot[bot] 774be48155 chore(deps): update framer-motion requirement from ^12.42.2 to ^12.43.0
Updates the requirements on [framer-motion](https://github.com/motiondivision/motion) to permit the latest version.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.42.2...v12.43.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 12.43.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 00:08:44 +00:00
dependabot[bot] dcff88ec7b chore(deps-dev): bump @biomejs/biome in the biome group
Bumps the biome group with 1 update: [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome).


Updates `@biomejs/biome` from 2.5.5 to 2.5.6
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.6/packages/@biomejs/biome)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.5.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: biome
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-29 00:08:08 +00:00
mytheclipsebotreview[bot] 407aa7b899 Auto-merge PR #7
chore(deps): update shadcn requirement from ^4.15.0 to ^4.16.0
2026-07-28 00:11:12 +00:00
dependabot[bot] 3337a3cc27 chore(deps): update shadcn requirement from ^4.15.0 to ^4.16.0
Updates the requirements on [shadcn](https://github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn) to permit the latest version.
- [Release notes](https://github.com/shadcn-ui/ui/releases)
- [Changelog](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/CHANGELOG.md)
- [Commits](https://github.com/shadcn-ui/ui/commits/shadcn@4.16.0/packages/shadcn)

---
updated-dependencies:
- dependency-name: shadcn
  dependency-version: 4.16.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-28 00:09:32 +00:00
mytheclipsebotreview[bot] e5331bdc01 Auto-merge PR #6
chore(deps): update lucide-react requirement from ^1.26.0 to ^1.27.0
2026-07-27 00:21:08 +00:00
mytheclipsebotreview[bot] a803849cba Auto-merge PR #5
chore(deps): update shadcn requirement from ^4.14.1 to ^4.15.0
2026-07-27 00:21:03 +00:00
dependabot[bot] e006bc9c0b chore(deps): update lucide-react requirement from ^1.26.0 to ^1.27.0
Updates the requirements on [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) to permit the latest version.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.27.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.27.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 00:19:18 +00:00
dependabot[bot] 21056c72f3 chore(deps): update shadcn requirement from ^4.14.1 to ^4.15.0
Updates the requirements on [shadcn](https://github.com/shadcn-ui/ui/tree/HEAD/packages/shadcn) to permit the latest version.
- [Release notes](https://github.com/shadcn-ui/ui/releases)
- [Changelog](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/CHANGELOG.md)
- [Commits](https://github.com/shadcn-ui/ui/commits/shadcn@4.15.0/packages/shadcn)

---
updated-dependencies:
- dependency-name: shadcn
  dependency-version: 4.15.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 00:19:09 +00:00
5 changed files with 260 additions and 144 deletions
+10
View File
@@ -5,6 +5,16 @@ const nextConfig: NextConfig = {
turbopack: {
root: process.cwd(),
},
// Nix store is read-only at runtime; Next.js tries to mkdir
// <distDir>/cache/images for the on-disk image optimizer LRU and
// crashes with EACCES unhandledRejection on every optimized image
// request. Disable the disk cache (and disable ISR flush which gates it).
images: {
maximumDiskCacheSize: 0,
},
experimental: {
isrFlushToDisk: false,
},
};
export default nextConfig;
+9 -9
View File
@@ -10,30 +10,30 @@
"format": "biome format --write"
},
"dependencies": {
"@base-ui/react": "^1.6.0",
"@shadcn/react": "^0.2.1",
"@base-ui/react": "^1.7.0",
"@shadcn/react": "^0.3.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.4.0",
"embla-carousel-react": "^8.6.0",
"framer-motion": "^12.42.2",
"framer-motion": "^13.1.0",
"input-otp": "^1.4.2",
"lucide-react": "^1.26.0",
"next": "16.2.12",
"lucide-react": "^1.31.0",
"next": "16.3.1",
"next-themes": "^0.4.6",
"react": "19.2.8",
"react-day-picker": "^10.0.1",
"react-dom": "19.2.8",
"react-resizable-panels": "^4.12.2",
"react-resizable-panels": "^4.12.3",
"recharts": "3.10.1",
"shadcn": "^4.14.1",
"sonner": "^2.0.7",
"shadcn": "^4.18.0",
"sonner": "^2.0.8",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@biomejs/biome": "2.5.5",
"@biomejs/biome": "2.5.9",
"@tailwindcss/postcss": "^4",
"@types/node": "^26",
"@types/react": "^19",
+137 -126
View File
@@ -1,16 +1,10 @@
import http from "node:http";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { NextResponse } from "next/server";
const JAEGER = "http://jaeger:16686";
const PROMETHEUS = "http://prometheus:9090";
const DOCKER_SOCK = "/var/run/docker.sock";
const execFileAsync = promisify(execFile);
interface Container {
Names: string[];
State: string;
Labels: Record<string, string>;
NetworkSettings?: { Networks?: Record<string, unknown> };
}
const PROMETHEUS = "http://127.0.0.1:9090";
interface Trace {
service: string;
@@ -26,24 +20,70 @@ interface Service {
hasWeb: boolean;
}
function dockerFetch(path: string): Promise<unknown> {
return new Promise((resolve, reject) => {
http
.get({ socketPath: DOCKER_SOCK, path }, (res) => {
let data = "";
res.on("data", (c: string) => {
data += c;
});
res.on("end", () => {
try {
resolve(JSON.parse(data));
} catch {
resolve(null);
}
});
})
.on("error", reject);
});
// Service-owning systemd units that should show up on the dashboard.
// GMW, Booster, etc. are listed even though they are headless (no web).
const MONITORED_UNITS = [
"caddy",
"9router",
"booster-role",
"gmw-backend",
"gmw-discord-gateway",
"hub",
"lidm-backend",
"lidm-frontend",
"llm-api",
"nats",
"node-exporter",
"otel",
"pr-agent-server",
"prometheus",
"scraper",
"teleuploader",
"tools-frontend",
"tools-gateway",
"tools-workers",
"zeavis-api",
"zeavis-ml-service",
"zeavis-web",
];
// Units with a public HTTPS site behind Caddy.
const WEB_UNITS = new Set([
"caddy",
"9router",
"hub",
"lidm-frontend",
"pr-agent-server",
"scraper",
"teleuploader",
"tools-frontend",
"zeavis-web",
]);
async function systemdServices(): Promise<Service[]> {
const services: Service[] = [];
for (const unit of MONITORED_UNITS) {
try {
const { stdout } = await execFileAsync("systemctl", [
"show",
`${unit}.service`,
"-p",
"ActiveState",
"-p",
"LoadState",
"--no-pager",
]);
const state = stdout.match(/ActiveState=(\w+)/)?.[1] ?? "unknown";
services.push({
name: unit,
state: state === "active" ? "running" : state,
hasWeb: WEB_UNITS.has(unit),
});
} catch {
// unit doesn't exist — skip silently
}
}
return services;
}
async function fetchJSON(url: string): Promise<unknown> {
@@ -55,73 +95,6 @@ async function fetchJSON(url: string): Promise<unknown> {
}
}
function parseServices(containers: Container[]): Service[] {
const project = containers.find((c) => c.Labels["com.docker.compose.project"])
?.Labels["com.docker.compose.project"];
return containers
.filter((c) => {
if (!c.NetworkSettings?.Networks?.["app-shared-net"]) return false;
if (project && c.Labels["com.docker.compose.project"] !== project)
return false;
return true;
})
.map((c) => ({
name: c.Names[0].replace(/^\//, ""),
state: c.State,
hasWeb: Object.keys(c.Labels).some(
(k) => k.startsWith("traefik.http.routers.") && k.endsWith(".rule"),
),
}));
}
async function fetchTraces(): Promise<Trace[]> {
const svcRes = await fetchJSON(`${JAEGER}/api/services`);
if (!svcRes || !Array.isArray((svcRes as { data?: string[] }).data))
return [];
const now = Date.now() * 1000;
const start = now - 5 * 60 * 1_000_000;
const all: Trace[] = [];
for (const service of (svcRes as { data: string[] }).data) {
const d = await fetchJSON(
`${JAEGER}/api/traces?service=${encodeURIComponent(service)}&start=${start}&end=${now}&limit=5&lookback=5m`,
);
if (!d || !Array.isArray((d as { data?: unknown[] }).data)) continue;
for (const t of (
d as {
data: {
duration: number;
spans: {
operationName: string;
processID: string;
tags: { key: string; value: unknown }[];
}[];
processes: Record<string, { serviceName: string }>;
}[];
}
).data) {
if (!t.spans?.length) continue;
const span = t.spans[0];
const svc = t.processes[span.processID]?.serviceName || "unknown";
const hasError = t.spans.some((s) =>
s.tags?.some((tag) => tag.key === "error" && tag.value === true),
);
all.push({
service: svc,
operation: span.operationName,
duration: t.duration,
spans: t.spans.length,
hasError,
});
}
}
return all.sort((a, b) => b.duration - a.duration).slice(0, 20);
}
async function promRange(query: string, steps = 20): Promise<number[]> {
const now = Math.floor(Date.now() / 1000);
const u = `${PROMETHEUS}/api/v1/query_range?query=${encodeURIComponent(query)}&start=${now - 300}&end=${now}&step=${(300 / steps).toFixed(0)}`;
@@ -164,18 +137,20 @@ interface DashboardData {
errors: number[];
traceVolume: number[];
links: { url: string; label: string }[];
llm: {
reqRate: number | null;
tokRate: number | null;
tokSpeed: number | null;
uptime: number | null;
reqSpark: number[];
tokSpark: number[];
};
}
export async function GET() {
const [containersRaw] = await Promise.all([
dockerFetch("/containers/json?all=true") as Promise<Container[]>,
]);
const containers = Array.isArray(containersRaw) ? containersRaw : [];
const services = parseServices(containers);
const services = await systemdServices();
const [
traces,
cpu,
ram,
disk,
@@ -184,11 +159,11 @@ export async function GET() {
load15,
netIn,
netOut,
rps,
latency,
errors,
netInSpark,
loadSpark,
netOutSpark,
upstreamCount,
] = await Promise.all([
fetchTraces(),
promQuery(
`100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)`,
),
@@ -203,42 +178,78 @@ export async function GET() {
promQuery("node_load15"),
promQuery(`rate(node_network_receive_bytes_total{device!="lo"}[1m])`),
promQuery(`rate(node_network_transmit_bytes_total{device!="lo"}[1m])`),
promRange("sum(rate(traefik_service_requests_total[1m]))"),
promRange('sum(rate(node_network_receive_bytes_total{device!="lo"}[1m]))'),
promRange("avg(node_load1)"),
promRange('sum(rate(node_network_transmit_bytes_total{device!="lo"}[1m]))'),
promQuery("count(up)"),
]);
// ── Error rate (llm-api) & request rate (any /metrics service) ──
const [errRate, errSpark] = await Promise.all([
promQuery(`sum(rate(llm_api_errors_total[5m]))`),
promRange(`sum(rate(llm_api_errors_total[1m]))`),
]);
const reqRate = await promQuery(
`sum(rate(llm_api_requests_total[5m])) + sum(rate(http_server_request_count_total[5m]))`,
);
const reqSpark = await promRange(
`sum(rate(llm_api_requests_total[1m])) + sum(rate(http_server_request_count_total[1m]))`,
);
// ── LLM inference metrics (llm-api /metrics) ──
const [
llmReqRate,
llmTokRate,
llmTokSpeed,
llmUptime,
llmReqSpark,
llmTokSpark,
] = await Promise.all([
promQuery(
`sum(rate(llm_api_requests_total{service="llm-api"}[5m]))`,
),
promQuery(
`sum(rate(llm_api_completion_tokens_total{service="llm-api"}[5m]))`,
),
promQuery(
`avg(llm_api_tokens_per_second{service="llm-api"})`,
),
promQuery(`llm_api_uptime_seconds{service="llm-api"}`),
promRange(
"avg(traefik_service_request_duration_seconds_sum / traefik_service_request_duration_seconds_count) * 1000",
`sum(rate(llm_api_requests_total{service="llm-api"}[1m]))`,
),
promRange(
`sum(rate(llm_api_completion_tokens_total{service="llm-api"}[1m]))`,
),
promRange('sum(rate(traefik_service_requests_total{code=~"5.."}[1m]))'),
]);
const links: { url: string; label: string }[] = [
{ url: "/jaeger", label: "Jaeger UI" },
{ url: "https://github.com/asepharyana/asepharyana-hub", label: "GitHub" },
];
if (containers.some((c) => c.Names?.some((n) => n.includes("prometheus")))) {
links.push({ url: "/api/prometheus/targets", label: "Prometheus" });
}
links.push({
url: "https://github.com/asepharyana/asepharyana-hub",
label: "GitHub",
});
const domains = ["asepharyana.my.id", "asepharyana.web.id"];
const domains = ["asepharyana.my.id"];
for (const s of services) {
if (s.hasWeb && s.state === "running") {
links.push({ url: `https://${s.name}.${domains[0]}`, label: s.name });
}
}
const traceVolume = [traces.length];
const data: DashboardData = {
services,
traces,
traces: [],
node: { cpu, ram, disk, load1, load5, load15, netIn, netOut },
rps,
latency,
errors,
traceVolume,
rps: reqSpark,
latency: loadSpark,
errors: errSpark,
traceVolume: netInSpark,
links,
llm: {
reqRate: llmReqRate,
tokRate: llmTokRate,
tokSpeed: llmTokSpeed,
uptime: llmUptime,
reqSpark: llmReqSpark,
tokSpark: llmTokSpark,
},
};
return NextResponse.json(data);
+85 -9
View File
@@ -10,6 +10,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { AnimatedNumber } from "@/components/ui/motion-primitives";
import {
type DashboardData,
fmtUptime,
gaugeColor,
safeDur,
serviceIndicator,
@@ -59,8 +60,8 @@ export default function Dashboard() {
data?.services.filter((s) => s.state === "running").length ?? 0;
const degraded = (data?.services.length ?? 0) - running;
const hasNode = data?.node.cpu !== null || data?.node.ram !== null;
const hasTraffik =
(data?.rps?.length ?? 0) > 0 || (data?.latency?.length ?? 0) > 0;
const hasTraffic =
(data?.rps?.length ?? 0) > 0 || (data?.errors?.length ?? 0) > 0;
const node = data?.node;
return (
@@ -146,7 +147,15 @@ export default function Dashboard() {
label="Traces"
color="text-blue-400"
/>
<StatBox value={0} label="Errors" color="text-red-400" />
<StatBox
value={
data?.errors?.length
? data.errors[data.errors.length - 1].toFixed(2)
: undefined
}
label="LLM err/s"
color="text-red-400"
/>
</div>
</CardContent>
</Card>
@@ -230,8 +239,75 @@ export default function Dashboard() {
</motion.div>
)}
{/* LLM Inference */}
<motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>LLM Inference</CardTitle>
<Badge variant="secondary" className="font-mono text-[10px] font-normal">
{data?.llm.uptime != null
? `${fmtUptime(data.llm.uptime)} up`
: "no data"}
</Badge>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-1.5">
<StatBox
value={
data?.llm.reqRate != null
? data.llm.reqRate.toFixed(1)
: undefined
}
label="Req/s (5m)"
color="text-blue-400"
/>
<StatBox
value={
data?.llm.tokRate != null
? `${data.llm.tokRate.toFixed(0)}`
: undefined
}
label="Tokens/s (5m)"
color="text-green-400"
/>
<StatBox
value={
data?.llm.tokSpeed != null
? `${data.llm.tokSpeed.toFixed(0)}`
: undefined
}
label="Gen tok/s"
color="text-purple-400"
/>
<StatBox
value={data?.llm.reqSpark?.length ? "live" : undefined}
label="Sparkline"
color="text-yellow-400"
/>
</div>
{data?.llm.reqSpark?.length ? (
<div className="mt-2">
<Sparkline data={data.llm.reqSpark} color="#58a6ff" />
</div>
) : (
<p className="mt-2 text-center text-[10px] text-muted-foreground">
No traffic yet &mdash; send a prompt on{" "}
<a
className="text-blue-400 underline"
href="https://ai.asepharyana.my.id"
target="_blank"
rel="noopener noreferrer"
>
ai.asepharyana.my.id
</a>
</p>
)}
</CardContent>
</Card>
</motion.div>
{/* Request Rate */}
{hasTraffik && (
{hasTraffic && (
<motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between">
@@ -249,15 +325,15 @@ export default function Dashboard() {
</motion.div>
)}
{/* Latency */}
{hasTraffik && (
{/* Load Average */}
{hasNode && (
<motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Latency</CardTitle>
<CardTitle>Load Average</CardTitle>
<Badge variant="secondary" className="text-[10px] font-normal">
{data?.latency?.length
? `${data.latency[data.latency.length - 1].toFixed(0)}ms`
? data.latency[data.latency.length - 1].toFixed(2)
: "-"}
</Badge>
</CardHeader>
@@ -269,7 +345,7 @@ export default function Dashboard() {
)}
{/* Error Rate */}
{hasTraffik && (
{hasTraffic && (
<motion.div variants={cardVariants}>
<Card className="transition-shadow duration-300 hover:shadow-md hover:shadow-border/20">
<CardHeader className="flex flex-row items-center justify-between">
+19
View File
@@ -30,6 +30,14 @@ export interface DashboardData {
errors: number[];
traceVolume: number[];
links: { url: string; label: string }[];
llm: {
reqRate: number | null;
tokRate: number | null;
tokSpeed: number | null;
uptime: number | null;
reqSpark: number[];
tokSpark: number[];
};
}
export function safeDur(us: number): string {
@@ -55,3 +63,14 @@ export function serviceIndicator(state: string): string {
return "bg-red-400";
}
}
export function fmtUptime(seconds: number): string {
const s = Math.max(0, Math.floor(seconds));
if (s < 60) return `${s}s`;
const m = Math.floor(s / 60);
if (m < 60) return `${m}m ${s % 60}s`;
const h = Math.floor(m / 60);
if (h < 24) return `${h}h ${m % 60}m`;
const d = Math.floor(h / 24);
return `${d}d ${h % 24}h`;
}