vibora 1.7.0 → 1.8.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/server/index.js CHANGED
@@ -7732,6 +7732,7 @@ var systemMetrics = sqliteTable("system_metrics", {
7732
7732
  cpuPercent: real("cpu_percent").notNull(),
7733
7733
  memoryUsedBytes: integer("memory_used_bytes").notNull(),
7734
7734
  memoryTotalBytes: integer("memory_total_bytes").notNull(),
7735
+ memoryCacheBytes: integer("memory_cache_bytes").notNull().default(0),
7735
7736
  diskUsedBytes: integer("disk_used_bytes").notNull(),
7736
7737
  diskTotalBytes: integer("disk_total_bytes").notNull()
7737
7738
  });
@@ -143455,9 +143456,47 @@ import { execSync as execSync5 } from "child_process";
143455
143456
 
143456
143457
  // server/services/metrics-collector.ts
143457
143458
  import os5 from "os";
143459
+ import fs7 from "fs";
143458
143460
  import { execSync as execSync4 } from "child_process";
143459
143461
  var COLLECT_INTERVAL = 5000;
143460
143462
  var RETENTION_HOURS = 24;
143463
+ function getMemoryInfo() {
143464
+ const total = os5.totalmem();
143465
+ try {
143466
+ const meminfo = fs7.readFileSync("/proc/meminfo", "utf-8");
143467
+ const values = {};
143468
+ for (const line of meminfo.split(`
143469
+ `)) {
143470
+ const match3 = line.match(/^(\w+):\s+(\d+)\s+kB/);
143471
+ if (match3) {
143472
+ values[match3[1]] = parseInt(match3[2], 10) * 1024;
143473
+ }
143474
+ }
143475
+ const memTotal = values["MemTotal"] || total;
143476
+ const memFree = values["MemFree"] || 0;
143477
+ const buffers = values["Buffers"] || 0;
143478
+ const cached = values["Cached"] || 0;
143479
+ const sReclaimable = values["SReclaimable"] || 0;
143480
+ const shmem = values["Shmem"] || 0;
143481
+ let cacheBuffers = buffers + cached + sReclaimable - shmem;
143482
+ if (cacheBuffers < 0) {
143483
+ cacheBuffers = 0;
143484
+ }
143485
+ const used = memTotal - memFree - buffers - cached - sReclaimable + shmem;
143486
+ return {
143487
+ total: memTotal,
143488
+ used: Math.max(used, 0),
143489
+ cache: cacheBuffers
143490
+ };
143491
+ } catch {
143492
+ const free = os5.freemem();
143493
+ return {
143494
+ total,
143495
+ used: total - free,
143496
+ cache: 0
143497
+ };
143498
+ }
143499
+ }
143461
143500
  var intervalId = null;
143462
143501
  var previousCpu = null;
143463
143502
  function getCpuSnapshot() {
@@ -143505,15 +143544,14 @@ function getDiskUsage() {
143505
143544
  function collectMetrics() {
143506
143545
  const timestamp = Math.floor(Date.now() / 1000);
143507
143546
  const cpuPercent = calculateCpuPercent();
143508
- const memoryTotal = os5.totalmem();
143509
- const memoryFree = os5.freemem();
143510
- const memoryUsed = memoryTotal - memoryFree;
143547
+ const memory = getMemoryInfo();
143511
143548
  const disk = getDiskUsage();
143512
143549
  db.insert(systemMetrics).values({
143513
143550
  timestamp,
143514
143551
  cpuPercent,
143515
- memoryUsedBytes: memoryUsed,
143516
- memoryTotalBytes: memoryTotal,
143552
+ memoryUsedBytes: memory.used,
143553
+ memoryTotalBytes: memory.total,
143554
+ memoryCacheBytes: memory.cache,
143517
143555
  diskUsedBytes: disk.used,
143518
143556
  diskTotalBytes: disk.total
143519
143557
  }).run();
@@ -143555,21 +143593,22 @@ function getMetrics(windowSeconds) {
143555
143593
  timestamp: row.timestamp,
143556
143594
  cpuPercent: row.cpuPercent,
143557
143595
  memoryUsedPercent: row.memoryTotalBytes > 0 ? row.memoryUsedBytes / row.memoryTotalBytes * 100 : 0,
143596
+ memoryCachePercent: row.memoryTotalBytes > 0 ? row.memoryCacheBytes / row.memoryTotalBytes * 100 : 0,
143558
143597
  diskUsedPercent: row.diskTotalBytes > 0 ? row.diskUsedBytes / row.diskTotalBytes * 100 : 0
143559
143598
  }));
143560
143599
  }
143561
143600
  function getCurrentMetrics() {
143562
- const memoryTotal = os5.totalmem();
143563
- const memoryFree = os5.freemem();
143564
- const memoryUsed = memoryTotal - memoryFree;
143601
+ const memory = getMemoryInfo();
143565
143602
  const disk = getDiskUsage();
143566
143603
  const latest = db.select().from(systemMetrics).orderBy(systemMetrics.timestamp).limit(1).all();
143567
143604
  return {
143568
143605
  cpu: latest.length > 0 ? latest[0].cpuPercent : 0,
143569
143606
  memory: {
143570
- total: memoryTotal,
143571
- used: memoryUsed,
143572
- usedPercent: memoryUsed / memoryTotal * 100
143607
+ total: memory.total,
143608
+ used: memory.used,
143609
+ cache: memory.cache,
143610
+ usedPercent: memory.total > 0 ? memory.used / memory.total * 100 : 0,
143611
+ cachePercent: memory.total > 0 ? memory.cache / memory.total * 100 : 0
143573
143612
  },
143574
143613
  disk: {
143575
143614
  total: disk.total,
@@ -143797,6 +143836,156 @@ monitoringRoutes.post("/claude-instances/:pid/kill-pid", (c) => {
143797
143836
  return c.json({ error: message }, 500);
143798
143837
  }
143799
143838
  });
143839
+ monitoringRoutes.get("/top-processes", (c) => {
143840
+ const sortBy = c.req.query("sort") || "memory";
143841
+ const limit = parseInt(c.req.query("limit") || "10", 10);
143842
+ try {
143843
+ const memTotal = parseInt(readFileSync7("/proc/meminfo", "utf-8").match(/MemTotal:\s+(\d+)/)?.[1] || "0", 10) * 1024;
143844
+ const processes = [];
143845
+ const procDirs = readdirSync7("/proc").filter((d) => /^\d+$/.test(d));
143846
+ for (const pidStr of procDirs) {
143847
+ const pid = parseInt(pidStr, 10);
143848
+ try {
143849
+ const status = readFileSync7(`/proc/${pid}/status`, "utf-8");
143850
+ const nameMatch = status.match(/Name:\s+(.+)/);
143851
+ const rssMatch = status.match(/VmRSS:\s+(\d+)\s+kB/);
143852
+ if (!nameMatch || !rssMatch)
143853
+ continue;
143854
+ const name = nameMatch[1].trim();
143855
+ const memoryKB = parseInt(rssMatch[1], 10);
143856
+ const memoryMB = memoryKB / 1024;
143857
+ const memoryPercent = memTotal > 0 ? memoryKB * 1024 / memTotal * 100 : 0;
143858
+ let command = "";
143859
+ try {
143860
+ command = readFileSync7(`/proc/${pid}/cmdline`, "utf-8").replace(/\0/g, " ").trim().slice(0, 200);
143861
+ } catch {
143862
+ command = name;
143863
+ }
143864
+ const cpuPercent = 0;
143865
+ processes.push({
143866
+ pid,
143867
+ name,
143868
+ command,
143869
+ cpuPercent: Math.round(cpuPercent * 10) / 10,
143870
+ memoryMB: Math.round(memoryMB * 10) / 10,
143871
+ memoryPercent: Math.round(memoryPercent * 10) / 10
143872
+ });
143873
+ } catch {
143874
+ continue;
143875
+ }
143876
+ }
143877
+ if (sortBy === "cpu") {
143878
+ processes.sort((a, b) => b.cpuPercent - a.cpuPercent);
143879
+ } else {
143880
+ processes.sort((a, b) => b.memoryMB - a.memoryMB);
143881
+ }
143882
+ return c.json(processes.slice(0, limit));
143883
+ } catch {
143884
+ try {
143885
+ const sortFlag = sortBy === "cpu" ? "-pcpu" : "-rss";
143886
+ const result = execSync5(`ps -eo pid,comm,args,%cpu,rss --sort=${sortFlag} --no-headers | head -${limit + 1}`, { encoding: "utf-8", timeout: 5000 });
143887
+ const memTotal = parseInt(execSync5("grep MemTotal /proc/meminfo", { encoding: "utf-8" }).match(/(\d+)/)?.[1] || "0", 10) * 1024;
143888
+ const processes = [];
143889
+ for (const line of result.trim().split(`
143890
+ `)) {
143891
+ const match3 = line.match(/^\s*(\d+)\s+(\S+)\s+(.+?)\s+([\d.]+)\s+(\d+)\s*$/);
143892
+ if (match3) {
143893
+ const memoryKB = parseInt(match3[5], 10);
143894
+ processes.push({
143895
+ pid: parseInt(match3[1], 10),
143896
+ name: match3[2],
143897
+ command: match3[3].trim().slice(0, 200),
143898
+ cpuPercent: parseFloat(match3[4]),
143899
+ memoryMB: Math.round(memoryKB / 1024 * 10) / 10,
143900
+ memoryPercent: memTotal > 0 ? Math.round(memoryKB * 1024 / memTotal * 1000) / 10 : 0
143901
+ });
143902
+ }
143903
+ }
143904
+ return c.json(processes);
143905
+ } catch (fallbackErr) {
143906
+ const message = fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr);
143907
+ return c.json({ error: message }, 500);
143908
+ }
143909
+ }
143910
+ });
143911
+ monitoringRoutes.get("/docker-stats", (c) => {
143912
+ try {
143913
+ let result;
143914
+ let runtime = "docker";
143915
+ try {
143916
+ result = execSync5('docker stats --no-stream --format "{{json .}}"', {
143917
+ encoding: "utf-8",
143918
+ timeout: 1e4,
143919
+ stdio: ["pipe", "pipe", "pipe"]
143920
+ });
143921
+ } catch {
143922
+ try {
143923
+ result = execSync5('podman stats --no-stream --format "{{json .}}"', {
143924
+ encoding: "utf-8",
143925
+ timeout: 1e4,
143926
+ stdio: ["pipe", "pipe", "pipe"]
143927
+ });
143928
+ runtime = "podman";
143929
+ } catch {
143930
+ return c.json({ containers: [], available: false, runtime: null });
143931
+ }
143932
+ }
143933
+ const containers = [];
143934
+ for (const line of result.trim().split(`
143935
+ `)) {
143936
+ if (!line.trim())
143937
+ continue;
143938
+ try {
143939
+ const data = JSON.parse(line);
143940
+ const cpuStr = data.CPUPerc || "0%";
143941
+ const cpuPercent = parseFloat(cpuStr.replace("%", "")) || 0;
143942
+ const memUsageStr = data.MemUsage || "0B / 0B";
143943
+ const [usedStr, limitStr] = memUsageStr.split(" / ");
143944
+ const parseMemory = (str) => {
143945
+ const match3 = str.match(/([\d.]+)\s*(B|KB|KiB|MB|MiB|GB|GiB)/i);
143946
+ if (!match3)
143947
+ return 0;
143948
+ const value = parseFloat(match3[1]);
143949
+ const unit = match3[2].toLowerCase();
143950
+ switch (unit) {
143951
+ case "b":
143952
+ return value / (1024 * 1024);
143953
+ case "kb":
143954
+ case "kib":
143955
+ return value / 1024;
143956
+ case "mb":
143957
+ case "mib":
143958
+ return value;
143959
+ case "gb":
143960
+ case "gib":
143961
+ return value * 1024;
143962
+ default:
143963
+ return value;
143964
+ }
143965
+ };
143966
+ const memoryMB = parseMemory(usedStr);
143967
+ const memoryLimit = parseMemory(limitStr);
143968
+ const memPercStr = data.MemPerc || "0%";
143969
+ const memoryPercent = parseFloat(memPercStr.replace("%", "")) || 0;
143970
+ containers.push({
143971
+ id: (data.ID || data.Id || "").slice(0, 12),
143972
+ name: data.Name || data.Names || "unknown",
143973
+ cpuPercent: Math.round(cpuPercent * 10) / 10,
143974
+ memoryMB: Math.round(memoryMB * 10) / 10,
143975
+ memoryLimit: Math.round(memoryLimit * 10) / 10,
143976
+ memoryPercent: Math.round(memoryPercent * 10) / 10
143977
+ });
143978
+ } catch {
143979
+ continue;
143980
+ }
143981
+ }
143982
+ containers.sort((a, b) => b.memoryMB - a.memoryMB);
143983
+ return c.json({ containers, available: true, runtime });
143984
+ } catch (err) {
143985
+ const message = err instanceof Error ? err.message : String(err);
143986
+ return c.json({ error: message }, 500);
143987
+ }
143988
+ });
143800
143989
 
143801
143990
  // server/app.ts
143802
143991
  function getDistPath() {