opencode-system-metrics-tui 0.1.8 → 0.1.11
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 +19 -15
- package/dist/tui.js +159 -18
- package/package.json +2 -1
- package/scripts/build.ts +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Install globally in OpenCode
|
|
4
4
|
|
|
5
5
|
```powershell
|
|
6
|
-
opencode plugin -g opencode-system-metrics-tui@0.1.
|
|
6
|
+
opencode plugin -g opencode-system-metrics-tui@0.1.11 --force
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
This is the primary installation path. The version must match `package.json`; `--force` asks OpenCode to refresh its package cache. The helper below skips OpenCode when the expected artifact is already current. Verify the actual installed artifact afterward:
|
|
@@ -31,7 +31,7 @@ The README is available in **Español**, **English**, and **Português**.
|
|
|
31
31
|
- RAM: memoria usada, total y porcentaje.
|
|
32
32
|
- GPU: utilización y temperatura.
|
|
33
33
|
- GPU VRAM: memoria usada, total y porcentaje.
|
|
34
|
-
- En Apple Silicon, la fila se muestra como **
|
|
34
|
+
- En Apple Silicon, la fila se muestra como **RAM** y usa los contadores generales de memoria del sistema.
|
|
35
35
|
- Red: velocidad de descarga y subida en tiempo real.
|
|
36
36
|
- CPU, RAM y red se consultan con una cadencia general de 2 segundos; GPU, VRAM y temperaturas usan una caché expirable de 10 segundos para reducir el coste sin congelar los sensores.
|
|
37
37
|
- Colores compatibles con el tema activo de OpenCode.
|
|
@@ -40,7 +40,8 @@ The README is available in **Español**, **English**, and **Português**.
|
|
|
40
40
|
- Soporte para Linux, macOS y Windows cuando el sistema expone las métricas.
|
|
41
41
|
- En macOS, la utilización de GPU usa `ioreg` y las temperaturas usan el helper de Stats si está instalado; si cualquiera de ellos falta, esa métrica queda como no disponible sin interrumpir el plugin. En Intel se conserva el fallback de GPU discreta de `systeminformation`.
|
|
42
42
|
- En Windows, la temperatura de CPU requiere LibreHardwareMonitor ejecutándose como administrador con **Remote Web Server** activo en `http://127.0.0.1:8085`.
|
|
43
|
-
- En Windows, la velocidad de red usa
|
|
43
|
+
- En Windows, la velocidad de red usa una llamada nativa `GetIfTable2` de `iphlpapi.dll` mediante Koffi; la ruta PowerShell queda como fallback acotado si la API nativa no está disponible.
|
|
44
|
+
- La agregación nativa incluye interfaces de hardware activas, excluye interfaces de filtro, loopback y túnel, y suma sus contadores `InOctets`/`OutOctets`.
|
|
44
45
|
- Las lecturas opcionales de Windows se hacen bajo demanda, con timeout y caché; no hay timers globales de PowerShell.
|
|
45
46
|
- La detección de Nerd Font en Linux/macOS está limitada a rutas conocidas, 2 niveles de profundidad y 256 entradas por directorio; una ruta ausente o inaccesible usa Unicode. Windows no escanea fuentes salvo con `OPENCODE_MONITOR_NERD_FONT=1`.
|
|
46
47
|
- Si una fuente de métricas no responde a tiempo, su intento en caché se abandona de forma segura para permitir reintentos sin cancelar APIs que no aceptan `AbortSignal`.
|
|
@@ -93,7 +94,7 @@ npm publish --access public
|
|
|
93
94
|
En otro equipo:
|
|
94
95
|
|
|
95
96
|
```bash
|
|
96
|
-
opencode plugin opencode-system-metrics-tui@0.1.
|
|
97
|
+
opencode plugin opencode-system-metrics-tui@0.1.11
|
|
97
98
|
```
|
|
98
99
|
|
|
99
100
|
El paquete exporta tanto la raíz (`opencode-system-metrics-tui`) como `./tui`; ambas rutas cargan el mismo bundle TUI.
|
|
@@ -103,8 +104,8 @@ El instalador de OpenCode configura el plugin TUI automáticamente. Reinicia Ope
|
|
|
103
104
|
Publicar en npm e instalar en OpenCode son pasos distintos:
|
|
104
105
|
|
|
105
106
|
- `npm publish --access public` publica el paquete en npm.
|
|
106
|
-
- `opencode plugin opencode-system-metrics-tui@0.1.
|
|
107
|
-
- `opencode plugin -g opencode-system-metrics-tui@0.1.
|
|
107
|
+
- `opencode plugin opencode-system-metrics-tui@0.1.11` lo instala solo en el proyecto actual.
|
|
108
|
+
- `opencode plugin -g opencode-system-metrics-tui@0.1.11 --force` lo instala globalmente para todos los proyectos.
|
|
108
109
|
|
|
109
110
|
### Verificación
|
|
110
111
|
|
|
@@ -126,7 +127,7 @@ npm run build
|
|
|
126
127
|
- RAM: used memory, total memory, and percentage.
|
|
127
128
|
- GPU: utilization and temperature.
|
|
128
129
|
- GPU VRAM: used memory, total memory, and percentage.
|
|
129
|
-
- On Apple Silicon, the row is labeled **
|
|
130
|
+
- On Apple Silicon, the row is labeled **RAM** and uses the system-wide memory counters.
|
|
130
131
|
- Network: live download and upload speeds.
|
|
131
132
|
- CPU, RAM, and network use the 2-second general cadence; GPU, VRAM, and temperatures use an expiring 10-second cache to reduce cost without freezing sensors.
|
|
132
133
|
- Uses the active OpenCode theme colors.
|
|
@@ -135,7 +136,8 @@ npm run build
|
|
|
135
136
|
- Supports Linux, macOS, and Windows when the operating system exposes the metrics.
|
|
136
137
|
- On macOS, GPU utilization uses `ioreg` and temperatures use the Stats helper when installed; missing helpers leave only that metric unavailable without interrupting the plugin. Intel retains the discrete-GPU `systeminformation` fallback.
|
|
137
138
|
- On Windows, CPU temperature requires LibreHardwareMonitor running as administrator with **Remote Web Server** enabled at `http://127.0.0.1:8085`.
|
|
138
|
-
- On Windows, network speed uses
|
|
139
|
+
- On Windows, network speed uses one native `GetIfTable2` call from `iphlpapi.dll` through Koffi; the PowerShell path remains only as a bounded fallback when the native API cannot load.
|
|
140
|
+
- Native aggregation includes active hardware interfaces, excludes filter, loopback, and tunnel interfaces, and sums their `InOctets`/`OutOctets` counters.
|
|
139
141
|
- Optional Windows reads are on demand, timeout-bounded, and cached; no global PowerShell timers are used.
|
|
140
142
|
- Linux/macOS Nerd Font detection is limited to known paths, two directory levels, and 256 entries per directory; missing or inaccessible paths safely fall back to Unicode. Windows does not scan fonts unless `OPENCODE_MONITOR_NERD_FONT=1` is set.
|
|
141
143
|
- When a metric source does not respond in time, its cache attempt is safely abandoned so retries remain possible without cancelling APIs that do not accept `AbortSignal`.
|
|
@@ -188,7 +190,7 @@ npm publish --access public
|
|
|
188
190
|
On another machine:
|
|
189
191
|
|
|
190
192
|
```bash
|
|
191
|
-
opencode plugin opencode-system-metrics-tui@0.1.
|
|
193
|
+
opencode plugin opencode-system-metrics-tui@0.1.11
|
|
192
194
|
```
|
|
193
195
|
|
|
194
196
|
The package exports both the root (`opencode-system-metrics-tui`) and `./tui`; both paths load the same TUI bundle.
|
|
@@ -198,8 +200,8 @@ The OpenCode installer configures the TUI plugin automatically. Restart OpenCode
|
|
|
198
200
|
Publishing to npm and installing in OpenCode are separate steps:
|
|
199
201
|
|
|
200
202
|
- `npm publish --access public` publishes the package to npm.
|
|
201
|
-
- `opencode plugin opencode-system-metrics-tui@0.1.
|
|
202
|
-
- `opencode plugin -g opencode-system-metrics-tui@0.1.
|
|
203
|
+
- `opencode plugin opencode-system-metrics-tui@0.1.11` installs it for the current project only.
|
|
204
|
+
- `opencode plugin -g opencode-system-metrics-tui@0.1.11 --force` installs it globally for all projects.
|
|
203
205
|
|
|
204
206
|
### Verification
|
|
205
207
|
|
|
@@ -221,6 +223,7 @@ npm run build
|
|
|
221
223
|
- RAM: memória usada, total e porcentagem.
|
|
222
224
|
- GPU: utilização e temperatura.
|
|
223
225
|
- GPU VRAM: memória usada, total e porcentagem.
|
|
226
|
+
- No Apple Silicon, a linha de memória compartilhada é exibida como **RAM** e usa os contadores gerais de memória do sistema.
|
|
224
227
|
- Rede: velocidades de download e upload em tempo real.
|
|
225
228
|
- CPU, RAM e rede usam a cadência geral de 2 segundos; GPU, VRAM e temperaturas usam uma cache expirável de 10 segundos para reduzir o custo sem congelar os sensores.
|
|
226
229
|
- Usa as cores do tema ativo do OpenCode.
|
|
@@ -228,7 +231,8 @@ npm run build
|
|
|
228
231
|
- No Windows, ícones Unicode visíveis são usados por padrão porque o OpenCode não consegue detectar a fonte ativa do terminal.
|
|
229
232
|
- Suporte para Linux, macOS e Windows quando o sistema disponibiliza as métricas.
|
|
230
233
|
- No Windows, a temperatura da CPU requer o LibreHardwareMonitor executado como administrador com o **Remote Web Server** ativo em `http://127.0.0.1:8085`.
|
|
231
|
-
- No Windows, a velocidade da rede usa o PowerShell
|
|
234
|
+
- No Windows, a velocidade da rede usa uma chamada nativa `GetIfTable2` de `iphlpapi.dll` via Koffi; o PowerShell permanece apenas como fallback limitado quando a API nativa não pode ser carregada.
|
|
235
|
+
- A agregação nativa inclui interfaces de hardware ativas, exclui interfaces de filtro, loopback e túnel, e soma os contadores `InOctets`/`OutOctets`.
|
|
232
236
|
- As leituras opcionais do Windows são sob demanda, têm timeout e cache; não há timers globais do PowerShell.
|
|
233
237
|
- A detecção de Nerd Font no Linux/macOS é limitada a caminhos conhecidos, dois níveis de profundidade e 256 entradas por diretório; caminhos ausentes ou inacessíveis usam Unicode. O Windows não verifica fontes sem `OPENCODE_MONITOR_NERD_FONT=1`.
|
|
234
238
|
- Quando uma fonte de métricas não responde a tempo, a tentativa em cache é abandonada com segurança para permitir novas tentativas sem cancelar APIs que não aceitam `AbortSignal`.
|
|
@@ -281,7 +285,7 @@ npm publish --access public
|
|
|
281
285
|
Em outro computador:
|
|
282
286
|
|
|
283
287
|
```bash
|
|
284
|
-
opencode plugin opencode-system-metrics-tui@0.1.
|
|
288
|
+
opencode plugin opencode-system-metrics-tui@0.1.11
|
|
285
289
|
```
|
|
286
290
|
|
|
287
291
|
O pacote exporta tanto a raiz (`opencode-system-metrics-tui`) quanto `./tui`; os dois caminhos carregam o mesmo bundle TUI.
|
|
@@ -291,8 +295,8 @@ O instalador do OpenCode configura o plugin TUI automaticamente. Reinicie o Open
|
|
|
291
295
|
Publicar no npm e instalar no OpenCode são etapas diferentes:
|
|
292
296
|
|
|
293
297
|
- `npm publish --access public` publica o pacote no npm.
|
|
294
|
-
- `opencode plugin opencode-system-metrics-tui@0.1.
|
|
295
|
-
- `opencode plugin -g opencode-system-metrics-tui@0.1.
|
|
298
|
+
- `opencode plugin opencode-system-metrics-tui@0.1.11` instala o plugin apenas no projeto atual.
|
|
299
|
+
- `opencode plugin -g opencode-system-metrics-tui@0.1.11 --force` instala o plugin globalmente para todos os projetos.
|
|
296
300
|
|
|
297
301
|
### Verificação
|
|
298
302
|
|
package/dist/tui.js
CHANGED
|
@@ -6,7 +6,7 @@ import { insertNode as _$insertNode } from "@opentui/solid";
|
|
|
6
6
|
import { insert as _$insert } from "@opentui/solid";
|
|
7
7
|
import { setProp as _$setProp } from "@opentui/solid";
|
|
8
8
|
import { createElement as _$createElement } from "@opentui/solid";
|
|
9
|
-
import { createSignal, onCleanup, onMount } from "solid-js";
|
|
9
|
+
import { createMemo, createSignal, onCleanup, onMount } from "solid-js";
|
|
10
10
|
import { TextAttributes } from "@opentui/core";
|
|
11
11
|
|
|
12
12
|
// src/format.ts
|
|
@@ -39,6 +39,128 @@ function formatRate(bytesPerSecond) {
|
|
|
39
39
|
import { execFile } from "node:child_process";
|
|
40
40
|
import { promisify } from "node:util";
|
|
41
41
|
import si from "systeminformation";
|
|
42
|
+
|
|
43
|
+
// src/windows-network.ts
|
|
44
|
+
var IF_TYPE_SOFTWARE_LOOPBACK = 24;
|
|
45
|
+
var IF_TYPE_TUNNEL = 131;
|
|
46
|
+
var IF_OPER_STATUS_UP = 1;
|
|
47
|
+
var NET_IF_ACCESS_LOOPBACK = 1;
|
|
48
|
+
var ROWS_OFFSET = 8;
|
|
49
|
+
var nativeReader;
|
|
50
|
+
function toUint64(value) {
|
|
51
|
+
if (typeof value === "bigint" && value >= 0n)
|
|
52
|
+
return value;
|
|
53
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
|
|
54
|
+
return BigInt(value);
|
|
55
|
+
return 0n;
|
|
56
|
+
}
|
|
57
|
+
function mapWindowsNetworkRows(rows) {
|
|
58
|
+
return rows.reduce((total, row) => {
|
|
59
|
+
const flags = row.InterfaceAndOperStatusFlags;
|
|
60
|
+
const isHardware = typeof flags === "number" ? (flags & 1) !== 0 : flags?.HardwareInterface === 1;
|
|
61
|
+
const isFilter = typeof flags === "number" ? (flags & 2) !== 0 : flags?.FilterInterface === 1;
|
|
62
|
+
const isUsable = row.OperStatus === IF_OPER_STATUS_UP && row.AccessType !== NET_IF_ACCESS_LOOPBACK && row.Type !== IF_TYPE_SOFTWARE_LOOPBACK && row.Type !== IF_TYPE_TUNNEL;
|
|
63
|
+
if (!isHardware || isFilter || !isUsable)
|
|
64
|
+
return total;
|
|
65
|
+
return { rx: total.rx + toUint64(row.InOctets), tx: total.tx + toUint64(row.OutOctets) };
|
|
66
|
+
}, { rx: 0n, tx: 0n });
|
|
67
|
+
}
|
|
68
|
+
async function readWithFallback(primary, fallback) {
|
|
69
|
+
try {
|
|
70
|
+
return { value: await primary(), usedFallback: false };
|
|
71
|
+
} catch {
|
|
72
|
+
return { value: await fallback(), usedFallback: true };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function networkRate(current, previous, elapsedMs) {
|
|
76
|
+
if (previous === undefined)
|
|
77
|
+
return { rx: undefined, tx: undefined };
|
|
78
|
+
const seconds = Math.max(elapsedMs / 1000, 0.001);
|
|
79
|
+
const rx = current.rx >= previous.rx ? current.rx - previous.rx : 0n;
|
|
80
|
+
const tx = current.tx >= previous.tx ? current.tx - previous.tx : 0n;
|
|
81
|
+
return { rx: Number(rx) / seconds, tx: Number(tx) / seconds };
|
|
82
|
+
}
|
|
83
|
+
function defineNativeReader(koffi) {
|
|
84
|
+
const guid = koffi.struct("MIB_GUID", {
|
|
85
|
+
Data1: "uint32",
|
|
86
|
+
Data2: "uint16",
|
|
87
|
+
Data3: "uint16",
|
|
88
|
+
Data4: koffi.array("uint8", 8)
|
|
89
|
+
});
|
|
90
|
+
const row = koffi.struct("MIB_IF_ROW2", {
|
|
91
|
+
InterfaceLuid: "uint64",
|
|
92
|
+
InterfaceIndex: "uint32",
|
|
93
|
+
InterfaceGuid: guid,
|
|
94
|
+
Alias: koffi.array("char16_t", 257),
|
|
95
|
+
Description: koffi.array("char16_t", 257),
|
|
96
|
+
PhysicalAddressLength: "uint32",
|
|
97
|
+
PhysicalAddress: koffi.array("uint8", 32),
|
|
98
|
+
PermanentPhysicalAddress: koffi.array("uint8", 32),
|
|
99
|
+
Mtu: "uint32",
|
|
100
|
+
Type: "uint32",
|
|
101
|
+
TunnelType: "uint32",
|
|
102
|
+
MediaType: "uint32",
|
|
103
|
+
PhysicalMediumType: "uint32",
|
|
104
|
+
AccessType: "uint32",
|
|
105
|
+
DirectionType: "uint32",
|
|
106
|
+
InterfaceAndOperStatusFlags: "uint8",
|
|
107
|
+
OperStatus: "uint32",
|
|
108
|
+
AdminStatus: "uint32",
|
|
109
|
+
MediaConnectState: "uint32",
|
|
110
|
+
NetworkGuid: guid,
|
|
111
|
+
ConnectionType: "uint32",
|
|
112
|
+
TransmitLinkSpeed: "uint64",
|
|
113
|
+
ReceiveLinkSpeed: "uint64",
|
|
114
|
+
InOctets: "uint64",
|
|
115
|
+
InUcastPkts: "uint64",
|
|
116
|
+
InNUcastPkts: "uint64",
|
|
117
|
+
InDiscards: "uint64",
|
|
118
|
+
InErrors: "uint64",
|
|
119
|
+
InUnknownProtos: "uint64",
|
|
120
|
+
InUcastOctets: "uint64",
|
|
121
|
+
InMulticastOctets: "uint64",
|
|
122
|
+
InBroadcastOctets: "uint64",
|
|
123
|
+
OutOctets: "uint64",
|
|
124
|
+
OutUcastPkts: "uint64",
|
|
125
|
+
OutNUcastPkts: "uint64",
|
|
126
|
+
OutDiscards: "uint64",
|
|
127
|
+
OutErrors: "uint64",
|
|
128
|
+
OutUcastOctets: "uint64",
|
|
129
|
+
OutMulticastOctets: "uint64",
|
|
130
|
+
OutBroadcastOctets: "uint64",
|
|
131
|
+
OutQLen: "uint64"
|
|
132
|
+
});
|
|
133
|
+
if (koffi.sizeof(row) !== 1352)
|
|
134
|
+
throw new Error(`Unexpected MIB_IF_ROW2 size: ${koffi.sizeof(row)}`);
|
|
135
|
+
const iphlpapi = koffi.load("iphlpapi.dll");
|
|
136
|
+
const getIfTable2 = iphlpapi.func("uint32 __stdcall GetIfTable2(_Out_ void **Table)");
|
|
137
|
+
const freeMibTable = iphlpapi.func("void __stdcall FreeMibTable(void *Memory)");
|
|
138
|
+
return () => {
|
|
139
|
+
const output = [null];
|
|
140
|
+
const result = getIfTable2(output);
|
|
141
|
+
if (result !== 0 || output[0] === null)
|
|
142
|
+
throw new Error(`GetIfTable2 failed: ${result}`);
|
|
143
|
+
const table = output[0];
|
|
144
|
+
try {
|
|
145
|
+
const count = Number(koffi.decode(table, 0, "uint32"));
|
|
146
|
+
if (!Number.isSafeInteger(count) || count < 0 || count > 4096)
|
|
147
|
+
throw new Error(`Invalid interface count: ${count}`);
|
|
148
|
+
return Array.from({ length: count }, (_, index) => koffi.decode(table, ROWS_OFFSET + index * koffi.sizeof(row), row));
|
|
149
|
+
} finally {
|
|
150
|
+
freeMibTable(table);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async function loadNativeReader() {
|
|
155
|
+
const loaded = await import("koffi");
|
|
156
|
+
return defineNativeReader(loaded.default ?? loaded);
|
|
157
|
+
}
|
|
158
|
+
async function readWindowsNetworkCounters() {
|
|
159
|
+
nativeReader ??= loadNativeReader();
|
|
160
|
+
return mapWindowsNetworkRows((await nativeReader)());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/metrics.ts
|
|
42
164
|
var execFileAsync = promisify(execFile);
|
|
43
165
|
var DEFAULT_METRIC_TIMEOUT_MS = 1500;
|
|
44
166
|
var WINDOWS_MEMORY_TIMEOUT_MS = 5000;
|
|
@@ -64,7 +186,7 @@ function gpuMemoryLabel(architecture, platform = process.platform) {
|
|
|
64
186
|
if (platform !== "darwin")
|
|
65
187
|
return "GPU VRAM";
|
|
66
188
|
if (architecture === "arm64")
|
|
67
|
-
return "
|
|
189
|
+
return "RAM";
|
|
68
190
|
if (architecture === "x86_64")
|
|
69
191
|
return "GPU VRAM";
|
|
70
192
|
return "Memory";
|
|
@@ -139,7 +261,7 @@ function parseWindowsNetworkOutput(stdout) {
|
|
|
139
261
|
tx_bytes: finite(item.SentBytes) ?? 0
|
|
140
262
|
}));
|
|
141
263
|
}
|
|
142
|
-
async function
|
|
264
|
+
async function readWindowsNetworkFallback() {
|
|
143
265
|
const { stdout } = await execFileAsync("powershell.exe", [
|
|
144
266
|
"-NoProfile",
|
|
145
267
|
"-NonInteractive",
|
|
@@ -286,20 +408,28 @@ var cachedNetwork = {
|
|
|
286
408
|
inFlight: undefined
|
|
287
409
|
};
|
|
288
410
|
var previousWindowsNetwork;
|
|
411
|
+
var previousNativeWindowsNetwork;
|
|
289
412
|
async function readWindowsNetworkMetrics() {
|
|
290
|
-
const samples = await readWindowsNetworkSample();
|
|
291
413
|
const timestamp = Date.now();
|
|
292
|
-
const
|
|
293
|
-
|
|
414
|
+
const fallback = async () => {
|
|
415
|
+
const samples = await readWindowsNetworkFallback();
|
|
416
|
+
const rx = samples.reduce((total, item) => total + (finite(item.rx_bytes) ?? 0), 0);
|
|
417
|
+
const tx = samples.reduce((total, item) => total + (finite(item.tx_bytes) ?? 0), 0);
|
|
418
|
+
return { rx: BigInt(rx), tx: BigInt(tx) };
|
|
419
|
+
};
|
|
420
|
+
const { value: counters, usedFallback } = await readWithFallback(readWindowsNetworkCounters, fallback);
|
|
421
|
+
if (!usedFallback) {
|
|
422
|
+
const rate = networkRate(counters, previousNativeWindowsNetwork?.counters, previousNativeWindowsNetwork === undefined ? 0 : timestamp - previousNativeWindowsNetwork.timestamp);
|
|
423
|
+
previousNativeWindowsNetwork = { timestamp, counters };
|
|
424
|
+
return [{ rx_bytes: Number(counters.rx), tx_bytes: Number(counters.tx), rx_sec: rate.rx, tx_sec: rate.tx }];
|
|
425
|
+
}
|
|
294
426
|
const seconds = previousWindowsNetwork === undefined ? undefined : Math.max((timestamp - previousWindowsNetwork.timestamp) / 1000, 0.001);
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
tx_sec: seconds === undefined ? undefined : Math.max(0, tx - previousWindowsNetwork.tx) / seconds
|
|
300
|
-
}];
|
|
427
|
+
const rx = Number(counters.rx);
|
|
428
|
+
const tx = Number(counters.tx);
|
|
429
|
+
const rxSec = seconds === undefined ? undefined : Math.max(0, rx - previousWindowsNetwork.rx) / seconds;
|
|
430
|
+
const txSec = seconds === undefined ? undefined : Math.max(0, tx - previousWindowsNetwork.tx) / seconds;
|
|
301
431
|
previousWindowsNetwork = { timestamp, rx, tx };
|
|
302
|
-
return
|
|
432
|
+
return [{ rx_bytes: rx, tx_bytes: tx, rx_sec: rxSec, tx_sec: txSec }];
|
|
303
433
|
}
|
|
304
434
|
async function readWindowsCpuTemperature() {
|
|
305
435
|
try {
|
|
@@ -515,6 +645,17 @@ function systemMetricsTitle() {
|
|
|
515
645
|
function MetricsPanel(props) {
|
|
516
646
|
onMount(startMetricsPolling);
|
|
517
647
|
onCleanup(stopMetricsPolling);
|
|
648
|
+
const gpuMemory = createMemo(() => {
|
|
649
|
+
const metrics = metricsState.sharedMetrics();
|
|
650
|
+
const unified = metrics.gpuMemoryIsUnified === true;
|
|
651
|
+
return {
|
|
652
|
+
icon: unified ? icons.ram : icons.vram,
|
|
653
|
+
label: gpuMemoryLabel(unified ? "arm64" : metrics.gpuMemoryIsUnified === false ? "x86_64" : undefined),
|
|
654
|
+
usedBytes: unified ? metrics.memoryUsedBytes : metrics.gpuMemoryUsedBytes,
|
|
655
|
+
totalBytes: unified ? metrics.memoryTotalBytes : metrics.gpuMemoryTotalBytes,
|
|
656
|
+
percent: unified ? metrics.memoryPercent : metrics.gpuMemoryPercent
|
|
657
|
+
};
|
|
658
|
+
});
|
|
518
659
|
return (() => {
|
|
519
660
|
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createTextNode(` `), _el$4 = _$createElement("box"), _el$5 = _$createElement("text"), _el$6 = _$createElement("text"), _el$8 = _$createElement("text"), _el$9 = _$createTextNode(` · `), _el$0 = _$createTextNode(` `), _el$1 = _$createElement("box"), _el$10 = _$createElement("text"), _el$11 = _$createElement("text"), _el$13 = _$createElement("text"), _el$14 = _$createTextNode(` / `), _el$15 = _$createTextNode(` (`), _el$16 = _$createTextNode(`)`), _el$17 = _$createElement("box"), _el$18 = _$createElement("text"), _el$19 = _$createElement("text"), _el$21 = _$createElement("text"), _el$22 = _$createTextNode(` · `), _el$23 = _$createTextNode(` `), _el$24 = _$createElement("box"), _el$25 = _$createElement("text"), _el$26 = _$createElement("text"), _el$27 = _$createTextNode(` `), _el$28 = _$createTextNode(` `), _el$29 = _$createElement("text"), _el$30 = _$createTextNode(` / `), _el$31 = _$createTextNode(` (`), _el$32 = _$createTextNode(`)`), _el$33 = _$createElement("box"), _el$34 = _$createElement("text"), _el$35 = _$createElement("text"), _el$37 = _$createElement("text"), _el$38 = _$createTextNode(`↓ `), _el$39 = _$createTextNode(` ↑ `);
|
|
520
661
|
_$insertNode(_el$, _el$2);
|
|
@@ -567,16 +708,16 @@ function MetricsPanel(props) {
|
|
|
567
708
|
_$insertNode(_el$24, _el$26);
|
|
568
709
|
_$insertNode(_el$24, _el$29);
|
|
569
710
|
_$setProp(_el$24, "flexDirection", "row");
|
|
570
|
-
_$insert(_el$25, () =>
|
|
711
|
+
_$insert(_el$25, () => gpuMemory().icon);
|
|
571
712
|
_$insertNode(_el$26, _el$27);
|
|
572
713
|
_$insertNode(_el$26, _el$28);
|
|
573
|
-
_$insert(_el$26, () =>
|
|
714
|
+
_$insert(_el$26, () => gpuMemory().label, _el$28);
|
|
574
715
|
_$insertNode(_el$29, _el$30);
|
|
575
716
|
_$insertNode(_el$29, _el$31);
|
|
576
717
|
_$insertNode(_el$29, _el$32);
|
|
577
|
-
_$insert(_el$29, () => formatGiB(
|
|
578
|
-
_$insert(_el$29, () => formatGiB(
|
|
579
|
-
_$insert(_el$29, () => formatPercent(
|
|
718
|
+
_$insert(_el$29, () => formatGiB(gpuMemory().usedBytes), _el$30);
|
|
719
|
+
_$insert(_el$29, () => formatGiB(gpuMemory().totalBytes), _el$31);
|
|
720
|
+
_$insert(_el$29, () => formatPercent(gpuMemory().percent), _el$32);
|
|
580
721
|
_$insertNode(_el$33, _el$34);
|
|
581
722
|
_$insertNode(_el$33, _el$35);
|
|
582
723
|
_$insertNode(_el$33, _el$37);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-system-metrics-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "OpenCode TUI sidebar plugin for live system metrics",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@opentui/core": "^0.5.10",
|
|
35
35
|
"@opentui/solid": "^0.5.10",
|
|
36
|
+
"koffi": "^3.2.1",
|
|
36
37
|
"solid-js": "^1.9.12",
|
|
37
38
|
"systeminformation": "^5.33.8"
|
|
38
39
|
},
|
package/scripts/build.ts
CHANGED
|
@@ -6,7 +6,7 @@ const result = await Bun.build({
|
|
|
6
6
|
target: "node",
|
|
7
7
|
format: "esm",
|
|
8
8
|
plugins: [solidPlugin],
|
|
9
|
-
external: ["@opencode-ai/plugin/tui", "@opentui/core", "@opentui/solid", "solid-js", "systeminformation"],
|
|
9
|
+
external: ["@opencode-ai/plugin/tui", "@opentui/core", "@opentui/solid", "koffi", "solid-js", "systeminformation"],
|
|
10
10
|
naming: "[name].js",
|
|
11
11
|
})
|
|
12
12
|
|