opencode-system-metrics-tui 0.1.4 → 0.1.6

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 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.3 --force
6
+ opencode plugin -g opencode-system-metrics-tui@0.1.6 --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. Verify the actual installed artifact afterward:
@@ -40,6 +40,8 @@ The README is available in **Español**, **English**, and **Português**.
40
40
  - En Windows, la temperatura de CPU requiere LibreHardwareMonitor ejecutándose como administrador con **Remote Web Server** activo en `http://127.0.0.1:8085`.
41
41
  - En Windows, la velocidad de red usa PowerShell y `Get-NetAdapterStatistics`; no agrega una dependencia npm.
42
42
  - Las lecturas opcionales de Windows se hacen bajo demanda, con timeout y caché; no hay timers globales de PowerShell.
43
+ - 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`.
44
+ - 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`.
43
45
 
44
46
  ### Requisitos
45
47
 
@@ -89,7 +91,7 @@ npm publish --access public
89
91
  En otro equipo:
90
92
 
91
93
  ```bash
92
- opencode plugin opencode-system-metrics-tui@0.1.3
94
+ opencode plugin opencode-system-metrics-tui@0.1.6
93
95
  ```
94
96
 
95
97
  El paquete exporta tanto la raíz (`opencode-system-metrics-tui`) como `./tui`; ambas rutas cargan el mismo bundle TUI.
@@ -99,8 +101,8 @@ El instalador de OpenCode configura el plugin TUI automáticamente. Reinicia Ope
99
101
  Publicar en npm e instalar en OpenCode son pasos distintos:
100
102
 
101
103
  - `npm publish --access public` publica el paquete en npm.
102
- - `opencode plugin opencode-system-metrics-tui@0.1.3` lo instala solo en el proyecto actual.
103
- - `opencode plugin -g opencode-system-metrics-tui@0.1.3 --force` lo instala globalmente para todos los proyectos.
104
+ - `opencode plugin opencode-system-metrics-tui@0.1.6` lo instala solo en el proyecto actual.
105
+ - `opencode plugin -g opencode-system-metrics-tui@0.1.6 --force` lo instala globalmente para todos los proyectos.
104
106
 
105
107
  ### Verificación
106
108
 
@@ -131,6 +133,8 @@ npm run build
131
133
  - On Windows, CPU temperature requires LibreHardwareMonitor running as administrator with **Remote Web Server** enabled at `http://127.0.0.1:8085`.
132
134
  - On Windows, network speed uses PowerShell and `Get-NetAdapterStatistics`; it adds no npm dependency.
133
135
  - Optional Windows reads are on demand, timeout-bounded, and cached; no global PowerShell timers are used.
136
+ - 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.
137
+ - 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`.
134
138
 
135
139
  ### Requirements
136
140
 
@@ -180,7 +184,7 @@ npm publish --access public
180
184
  On another machine:
181
185
 
182
186
  ```bash
183
- opencode plugin opencode-system-metrics-tui@0.1.3
187
+ opencode plugin opencode-system-metrics-tui@0.1.6
184
188
  ```
185
189
 
186
190
  The package exports both the root (`opencode-system-metrics-tui`) and `./tui`; both paths load the same TUI bundle.
@@ -190,8 +194,8 @@ The OpenCode installer configures the TUI plugin automatically. Restart OpenCode
190
194
  Publishing to npm and installing in OpenCode are separate steps:
191
195
 
192
196
  - `npm publish --access public` publishes the package to npm.
193
- - `opencode plugin opencode-system-metrics-tui@0.1.3` installs it for the current project only.
194
- - `opencode plugin -g opencode-system-metrics-tui@0.1.3 --force` installs it globally for all projects.
197
+ - `opencode plugin opencode-system-metrics-tui@0.1.6` installs it for the current project only.
198
+ - `opencode plugin -g opencode-system-metrics-tui@0.1.6 --force` installs it globally for all projects.
195
199
 
196
200
  ### Verification
197
201
 
@@ -222,6 +226,8 @@ npm run build
222
226
  - 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`.
223
227
  - No Windows, a velocidade da rede usa o PowerShell e `Get-NetAdapterStatistics`; nenhuma dependência npm é adicionada.
224
228
  - As leituras opcionais do Windows são sob demanda, têm timeout e cache; não há timers globais do PowerShell.
229
+ - 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`.
230
+ - 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`.
225
231
 
226
232
  ### Requisitos
227
233
 
@@ -271,7 +277,7 @@ npm publish --access public
271
277
  Em outro computador:
272
278
 
273
279
  ```bash
274
- opencode plugin opencode-system-metrics-tui@0.1.3
280
+ opencode plugin opencode-system-metrics-tui@0.1.6
275
281
  ```
276
282
 
277
283
  O pacote exporta tanto a raiz (`opencode-system-metrics-tui`) quanto `./tui`; os dois caminhos carregam o mesmo bundle TUI.
@@ -281,8 +287,8 @@ O instalador do OpenCode configura o plugin TUI automaticamente. Reinicie o Open
281
287
  Publicar no npm e instalar no OpenCode são etapas diferentes:
282
288
 
283
289
  - `npm publish --access public` publica o pacote no npm.
284
- - `opencode plugin opencode-system-metrics-tui@0.1.3` instala o plugin apenas no projeto atual.
285
- - `opencode plugin -g opencode-system-metrics-tui@0.1.3 --force` instala o plugin globalmente para todos os projetos.
290
+ - `opencode plugin opencode-system-metrics-tui@0.1.6` instala o plugin apenas no projeto atual.
291
+ - `opencode plugin -g opencode-system-metrics-tui@0.1.6 --force` instala o plugin globalmente para todos os projetos.
286
292
 
287
293
  ### Verificação
288
294
 
@@ -10,6 +10,8 @@ import { existsSync, readdirSync } from "node:fs";
10
10
  import { homedir } from "node:os";
11
11
  import { join as posixJoin, win32 } from "node:path";
12
12
  var NERD_FONT_FILE_PATTERN = /NerdFont[A-Za-z0-9-]*[-_][A-Za-z0-9-]+\.(?:ttf|otf)$/i;
13
+ var MAX_FONT_SCAN_DEPTH = 2;
14
+ var MAX_FONT_SCAN_ENTRIES = 256;
13
15
  function getFontDirectories(platform, home = homedir(), env = process.env) {
14
16
  if (platform === "darwin")
15
17
  return [posixJoin(home, "Library", "Fonts"), "/Library/Fonts", "/System/Library/Fonts"];
@@ -25,19 +27,23 @@ function isNerdFontFile(fileName) {
25
27
  }
26
28
  var isHackNerdFontFile = isNerdFontFile;
27
29
  function hasNerdFont(platform = process.platform, home = homedir(), env = process.env) {
28
- const containsFont = (directory) => {
30
+ if (platform === "win32" && env.OPENCODE_MONITOR_NERD_FONT !== "1")
31
+ return false;
32
+ const containsFont = (directory, depth) => {
33
+ if (depth > MAX_FONT_SCAN_DEPTH)
34
+ return false;
29
35
  if (!existsSync(directory))
30
36
  return false;
31
37
  try {
32
- return readdirSync(directory, { withFileTypes: true }).some((entry) => {
38
+ return readdirSync(directory, { withFileTypes: true }).slice(0, MAX_FONT_SCAN_ENTRIES).some((entry) => {
33
39
  const path = platform === "win32" ? win32.join(directory, entry.name) : posixJoin(directory, entry.name);
34
- return entry.isFile() ? isNerdFontFile(entry.name) : entry.isDirectory() && containsFont(path);
40
+ return entry.isFile() ? isNerdFontFile(entry.name) : entry.isDirectory() && containsFont(path, depth + 1);
35
41
  });
36
42
  } catch {
37
43
  return false;
38
44
  }
39
45
  };
40
- return getFontDirectories(platform, home, env).some(containsFont);
46
+ return getFontDirectories(platform, home, env).some((directory) => containsFont(directory, 0));
41
47
  }
42
48
  var hasHackNerdFont = hasNerdFont;
43
49
  var nerdFontIcons = {
package/dist/tui.js CHANGED
@@ -52,22 +52,31 @@ async function readLibreHardwareMonitorTemperature() {
52
52
  if (!response.ok)
53
53
  return;
54
54
  const root = await response.json();
55
+ if (root === null || typeof root !== "object")
56
+ return;
55
57
  const sensors = [];
56
58
  const visit = (node) => {
57
59
  if (node.Type === "Temperature" && node.Text !== undefined)
58
60
  sensors.push(node);
59
- for (const child of node.Children ?? [])
60
- visit(child);
61
+ for (const child of Array.isArray(node.Children) ? node.Children : []) {
62
+ if (child !== null && typeof child === "object")
63
+ visit(child);
64
+ }
61
65
  };
62
66
  visit(root);
63
67
  const cpuSensor = sensors.find((sensor) => sensor.Text === "CPU Package") ?? sensors.find((sensor) => sensor.Text === "Core Average") ?? sensors.find((sensor) => sensor.Text === "Core Max");
64
68
  return parseMonitorTemperature(cpuSensor?.Value);
65
69
  }
66
70
  function parseWindowsNetworkOutput(stdout) {
67
- const parsed = JSON.parse(stdout.trim());
68
- const rows = Array.isArray(parsed) ? parsed : [parsed];
71
+ let parsed;
72
+ try {
73
+ parsed = JSON.parse(stdout.trim());
74
+ } catch {
75
+ return [];
76
+ }
77
+ const rows = (Array.isArray(parsed) ? parsed : [parsed]).filter((item) => item !== null && typeof item === "object");
69
78
  return rows.map((item) => ({
70
- iface: item.Name,
79
+ iface: typeof item.Name === "string" ? item.Name : undefined,
71
80
  rx_bytes: finite(item.ReceivedBytes) ?? 0,
72
81
  tx_bytes: finite(item.SentBytes) ?? 0
73
82
  }));
@@ -126,14 +135,15 @@ function selectGpuMetrics(graphics) {
126
135
  gpuMemoryTotalBytes: null,
127
136
  gpuMemoryPercent: null
128
137
  };
129
- if (graphics === undefined)
138
+ if (graphics === undefined || graphics === null || !Array.isArray(graphics.controllers))
130
139
  return empty;
131
140
  const controller = graphics.controllers.map((item) => {
132
- const utilization = finite(item.utilizationGpu);
133
- const temperature = finite(item.temperatureGpu);
134
- const memoryTotal = finite(item.memoryTotal);
135
- const memoryFree = finite(item.memoryFree);
136
- const memoryUsed = finite(item.memoryUsed) ?? (memoryTotal !== null && memoryFree !== null ? Math.max(0, memoryTotal - memoryFree) : null);
141
+ const source = item ?? {};
142
+ const utilization = finite(source.utilizationGpu);
143
+ const temperature = finite(source.temperatureGpu);
144
+ const memoryTotal = finite(source.memoryTotal);
145
+ const memoryFree = finite(source.memoryFree);
146
+ const memoryUsed = finite(source.memoryUsed) ?? (memoryTotal !== null && memoryFree !== null ? Math.max(0, memoryTotal - memoryFree) : null);
137
147
  const hasMemory = memoryUsed !== null && memoryTotal !== null && memoryTotal > 0;
138
148
  return { utilization, temperature, memoryUsed, memoryTotal, hasMemory };
139
149
  }).filter(({ utilization, temperature, hasMemory }) => utilization !== null || temperature !== null || hasMemory).sort((left, right) => {
@@ -156,7 +166,7 @@ function selectGpuMetrics(graphics) {
156
166
  }
157
167
  return result;
158
168
  }
159
- function readCachedMetric(state, reader, cacheMs = SLOW_METRIC_CACHE_MS, now = Date.now(), unavailableCacheMs = cacheMs) {
169
+ function readCachedMetric(state, reader, cacheMs = SLOW_METRIC_CACHE_MS, now = Date.now(), unavailableCacheMs = cacheMs, timeoutMs) {
160
170
  if (state.inFlight !== undefined)
161
171
  return state.inFlight;
162
172
  if (state.lastFailureAt !== undefined && now - state.lastFailureAt < unavailableCacheMs) {
@@ -165,17 +175,23 @@ function readCachedMetric(state, reader, cacheMs = SLOW_METRIC_CACHE_MS, now = D
165
175
  if (now - state.lastAttemptAt < cacheMs)
166
176
  return Promise.resolve(state.value);
167
177
  state.lastAttemptAt = now;
168
- state.inFlight = reader().then((value) => {
169
- state.value = value;
170
- state.lastFailureAt = undefined;
171
- return value;
172
- }).catch(() => {
173
- state.lastFailureAt = now;
174
- return state.value;
175
- }).finally(() => {
176
- state.inFlight = undefined;
177
- });
178
- return state.inFlight;
178
+ let flight;
179
+ flight = (async () => {
180
+ try {
181
+ const value = timeoutMs === undefined ? await reader() : await withTimeout(reader(), timeoutMs);
182
+ state.value = value;
183
+ state.lastFailureAt = undefined;
184
+ return value;
185
+ } catch {
186
+ state.lastFailureAt = now;
187
+ return state.value;
188
+ } finally {
189
+ if (state.inFlight === flight)
190
+ state.inFlight = undefined;
191
+ }
192
+ })();
193
+ state.inFlight = flight;
194
+ return flight;
179
195
  }
180
196
  var cachedCpuTemperature = {
181
197
  value: undefined,
@@ -238,9 +254,9 @@ async function readMetrics() {
238
254
  withTimeout(si.mem(), 1500)
239
255
  ]);
240
256
  const [temperature, graphics, network] = await Promise.allSettled([
241
- withTimeout(readCachedMetric(cachedCpuTemperature, isWindows ? readWindowsCpuTemperature : () => si.cpuTemperature(), TEMPERATURE_CACHE_MS), 2500),
242
- withTimeout(readCachedMetric(cachedGraphics, () => si.graphics(), SLOW_METRIC_CACHE_MS), 2500),
243
- withTimeout(readCachedMetric(cachedNetwork, isWindows ? readWindowsNetworkMetrics : () => si.networkStats("*"), isWindows ? NETWORK_CACHE_MS : 2000, Date.now(), OPTIONAL_SOURCE_BACKOFF_MS), 1500)
257
+ readCachedMetric(cachedCpuTemperature, isWindows ? readWindowsCpuTemperature : () => si.cpuTemperature(), TEMPERATURE_CACHE_MS, Date.now(), TEMPERATURE_CACHE_MS, 2500),
258
+ readCachedMetric(cachedGraphics, () => si.graphics(), SLOW_METRIC_CACHE_MS, Date.now(), SLOW_METRIC_CACHE_MS, 2500),
259
+ readCachedMetric(cachedNetwork, isWindows ? readWindowsNetworkMetrics : () => si.networkStats("*"), isWindows ? NETWORK_CACHE_MS : 2000, Date.now(), OPTIONAL_SOURCE_BACKOFF_MS, 1500)
244
260
  ]);
245
261
  const cpuPercent = load.status === "fulfilled" ? finite(load.value.currentLoad) : null;
246
262
  const memoryTotalBytes = memory.status === "fulfilled" ? finite(memory.value.total) : null;
@@ -251,7 +267,7 @@ async function readMetrics() {
251
267
  let downloadBytesPerSecond = null;
252
268
  let uploadBytesPerSecond = null;
253
269
  if (network.status === "fulfilled" && network.value !== undefined) {
254
- const samples = network.value;
270
+ const samples = Array.isArray(network.value) ? network.value : [];
255
271
  const timestamp = Date.now();
256
272
  const rx = samples.reduce((total, item) => total + (finite(item.rx_bytes) ?? 0), 0);
257
273
  const tx = samples.reduce((total, item) => total + (finite(item.tx_bytes) ?? 0), 0);
@@ -290,6 +306,8 @@ import { existsSync, readdirSync } from "node:fs";
290
306
  import { homedir } from "node:os";
291
307
  import { join as posixJoin, win32 } from "node:path";
292
308
  var NERD_FONT_FILE_PATTERN = /NerdFont[A-Za-z0-9-]*[-_][A-Za-z0-9-]+\.(?:ttf|otf)$/i;
309
+ var MAX_FONT_SCAN_DEPTH = 2;
310
+ var MAX_FONT_SCAN_ENTRIES = 256;
293
311
  function getFontDirectories(platform, home = homedir(), env = process.env) {
294
312
  if (platform === "darwin")
295
313
  return [posixJoin(home, "Library", "Fonts"), "/Library/Fonts", "/System/Library/Fonts"];
@@ -305,19 +323,23 @@ function isNerdFontFile(fileName) {
305
323
  }
306
324
  var isHackNerdFontFile = isNerdFontFile;
307
325
  function hasNerdFont(platform = process.platform, home = homedir(), env = process.env) {
308
- const containsFont = (directory) => {
326
+ if (platform === "win32" && env.OPENCODE_MONITOR_NERD_FONT !== "1")
327
+ return false;
328
+ const containsFont = (directory, depth) => {
329
+ if (depth > MAX_FONT_SCAN_DEPTH)
330
+ return false;
309
331
  if (!existsSync(directory))
310
332
  return false;
311
333
  try {
312
- return readdirSync(directory, { withFileTypes: true }).some((entry) => {
334
+ return readdirSync(directory, { withFileTypes: true }).slice(0, MAX_FONT_SCAN_ENTRIES).some((entry) => {
313
335
  const path = platform === "win32" ? win32.join(directory, entry.name) : posixJoin(directory, entry.name);
314
- return entry.isFile() ? isNerdFontFile(entry.name) : entry.isDirectory() && containsFont(path);
336
+ return entry.isFile() ? isNerdFontFile(entry.name) : entry.isDirectory() && containsFont(path, depth + 1);
315
337
  });
316
338
  } catch {
317
339
  return false;
318
340
  }
319
341
  };
320
- return getFontDirectories(platform, home, env).some(containsFont);
342
+ return getFontDirectories(platform, home, env).some((directory) => containsFont(directory, 0));
321
343
  }
322
344
  var hasHackNerdFont = hasNerdFont;
323
345
  var nerdFontIcons = {
@@ -341,7 +363,8 @@ function shouldUseNerdFont(platform, detected, env = process.env) {
341
363
 
342
364
  // src/tui.tsx
343
365
  var REFRESH_INTERVAL_MS = 2000;
344
- var icons = getMetricIcons(shouldUseNerdFont(process.platform, hasNerdFont()));
366
+ var platform = process.platform;
367
+ var icons = getMetricIcons(shouldUseNerdFont(platform, platform === "win32" ? false : hasNerdFont()));
345
368
  var initialMetrics = {
346
369
  cpuPercent: null,
347
370
  memoryUsedBytes: null,
@@ -356,33 +379,43 @@ var initialMetrics = {
356
379
  downloadBytesPerSecond: null,
357
380
  uploadBytesPerSecond: null
358
381
  };
359
- var [sharedMetrics, setSharedMetrics] = createSignal(initialMetrics);
360
- var metricsTimer;
361
- var metricsConsumers = 0;
362
- var refreshing = false;
382
+ var METRICS_STATE_KEY = Symbol.for("opencode-monitor.system-metrics");
383
+ var globalMetrics = globalThis;
384
+ var metricsState = globalMetrics[METRICS_STATE_KEY] ?? (globalMetrics[METRICS_STATE_KEY] = {
385
+ ...(() => {
386
+ const [sharedMetrics, setSharedMetrics] = createSignal(initialMetrics);
387
+ return {
388
+ sharedMetrics,
389
+ setSharedMetrics
390
+ };
391
+ })(),
392
+ metricsTimer: undefined,
393
+ metricsConsumers: 0,
394
+ refreshing: false
395
+ });
363
396
  var refreshMetrics = async () => {
364
- if (refreshing)
397
+ if (metricsState.refreshing)
365
398
  return;
366
- refreshing = true;
399
+ metricsState.refreshing = true;
367
400
  try {
368
- setSharedMetrics(await readMetrics());
401
+ metricsState.setSharedMetrics(await readMetrics());
369
402
  } finally {
370
- refreshing = false;
403
+ metricsState.refreshing = false;
371
404
  }
372
405
  };
373
406
  function startMetricsPolling() {
374
- metricsConsumers += 1;
375
- if (metricsConsumers !== 1)
407
+ metricsState.metricsConsumers += 1;
408
+ if (metricsState.metricsConsumers !== 1)
376
409
  return;
377
410
  refreshMetrics();
378
- metricsTimer = setInterval(() => void refreshMetrics(), REFRESH_INTERVAL_MS);
411
+ metricsState.metricsTimer = setInterval(() => void refreshMetrics(), REFRESH_INTERVAL_MS);
379
412
  }
380
413
  function stopMetricsPolling() {
381
- metricsConsumers = Math.max(0, metricsConsumers - 1);
382
- if (metricsConsumers !== 0 || metricsTimer === undefined)
414
+ metricsState.metricsConsumers = Math.max(0, metricsState.metricsConsumers - 1);
415
+ if (metricsState.metricsConsumers !== 0 || metricsState.metricsTimer === undefined)
383
416
  return;
384
- clearInterval(metricsTimer);
385
- metricsTimer = undefined;
417
+ clearInterval(metricsState.metricsTimer);
418
+ metricsState.metricsTimer = undefined;
386
419
  }
387
420
  function systemMetricsTitle() {
388
421
  const locale = process.env.LC_ALL ?? process.env.LANGUAGE?.split(":")[0] ?? process.env.LANG ?? Intl.DateTimeFormat().resolvedOptions().locale;
@@ -420,9 +453,9 @@ function MetricsPanel(props) {
420
453
  _$insertNode(_el$6, _$createTextNode(` CPU `));
421
454
  _$insertNode(_el$8, _el$9);
422
455
  _$insertNode(_el$8, _el$0);
423
- _$insert(_el$8, () => formatPercent(sharedMetrics().cpuPercent), _el$9);
456
+ _$insert(_el$8, () => formatPercent(metricsState.sharedMetrics().cpuPercent), _el$9);
424
457
  _$insert(_el$8, () => icons.thermometer, _el$0);
425
- _$insert(_el$8, () => formatTemperature(sharedMetrics().cpuTemperatureCelsius), null);
458
+ _$insert(_el$8, () => formatTemperature(metricsState.sharedMetrics().cpuTemperatureCelsius), null);
426
459
  _$insertNode(_el$1, _el$10);
427
460
  _$insertNode(_el$1, _el$11);
428
461
  _$insertNode(_el$1, _el$13);
@@ -432,9 +465,9 @@ function MetricsPanel(props) {
432
465
  _$insertNode(_el$13, _el$14);
433
466
  _$insertNode(_el$13, _el$15);
434
467
  _$insertNode(_el$13, _el$16);
435
- _$insert(_el$13, () => formatGiB(sharedMetrics().memoryUsedBytes), _el$14);
436
- _$insert(_el$13, () => formatGiB(sharedMetrics().memoryTotalBytes), _el$15);
437
- _$insert(_el$13, () => formatPercent(sharedMetrics().memoryPercent), _el$16);
468
+ _$insert(_el$13, () => formatGiB(metricsState.sharedMetrics().memoryUsedBytes), _el$14);
469
+ _$insert(_el$13, () => formatGiB(metricsState.sharedMetrics().memoryTotalBytes), _el$15);
470
+ _$insert(_el$13, () => formatPercent(metricsState.sharedMetrics().memoryPercent), _el$16);
438
471
  _$insertNode(_el$17, _el$18);
439
472
  _$insertNode(_el$17, _el$19);
440
473
  _$insertNode(_el$17, _el$21);
@@ -443,9 +476,9 @@ function MetricsPanel(props) {
443
476
  _$insertNode(_el$19, _$createTextNode(` GPU `));
444
477
  _$insertNode(_el$21, _el$22);
445
478
  _$insertNode(_el$21, _el$23);
446
- _$insert(_el$21, () => formatPercent(sharedMetrics().gpuPercent), _el$22);
479
+ _$insert(_el$21, () => formatPercent(metricsState.sharedMetrics().gpuPercent), _el$22);
447
480
  _$insert(_el$21, () => icons.thermometer, _el$23);
448
- _$insert(_el$21, () => formatTemperature(sharedMetrics().gpuTemperatureCelsius), null);
481
+ _$insert(_el$21, () => formatTemperature(metricsState.sharedMetrics().gpuTemperatureCelsius), null);
449
482
  _$insertNode(_el$24, _el$25);
450
483
  _$insertNode(_el$24, _el$26);
451
484
  _$insertNode(_el$24, _el$28);
@@ -455,9 +488,9 @@ function MetricsPanel(props) {
455
488
  _$insertNode(_el$28, _el$29);
456
489
  _$insertNode(_el$28, _el$30);
457
490
  _$insertNode(_el$28, _el$31);
458
- _$insert(_el$28, () => formatGiB(sharedMetrics().gpuMemoryUsedBytes), _el$29);
459
- _$insert(_el$28, () => formatGiB(sharedMetrics().gpuMemoryTotalBytes), _el$30);
460
- _$insert(_el$28, () => formatPercent(sharedMetrics().gpuMemoryPercent), _el$31);
491
+ _$insert(_el$28, () => formatGiB(metricsState.sharedMetrics().gpuMemoryUsedBytes), _el$29);
492
+ _$insert(_el$28, () => formatGiB(metricsState.sharedMetrics().gpuMemoryTotalBytes), _el$30);
493
+ _$insert(_el$28, () => formatPercent(metricsState.sharedMetrics().gpuMemoryPercent), _el$31);
461
494
  _$insertNode(_el$32, _el$33);
462
495
  _$insertNode(_el$32, _el$34);
463
496
  _$insertNode(_el$32, _el$36);
@@ -466,8 +499,8 @@ function MetricsPanel(props) {
466
499
  _$insertNode(_el$34, _$createTextNode(` NET `));
467
500
  _$insertNode(_el$36, _el$37);
468
501
  _$insertNode(_el$36, _el$38);
469
- _$insert(_el$36, () => formatRate(sharedMetrics().downloadBytesPerSecond), _el$38);
470
- _$insert(_el$36, () => formatRate(sharedMetrics().uploadBytesPerSecond), null);
502
+ _$insert(_el$36, () => formatRate(metricsState.sharedMetrics().downloadBytesPerSecond), _el$38);
503
+ _$insert(_el$36, () => formatRate(metricsState.sharedMetrics().uploadBytesPerSecond), null);
471
504
  _$effect((_p$) => {
472
505
  var _v$ = props.theme.text, _v$2 = TextAttributes.BOLD, _v$3 = props.theme.success, _v$4 = props.theme.text, _v$5 = props.theme.textMuted, _v$6 = props.theme.success, _v$7 = props.theme.text, _v$8 = props.theme.textMuted, _v$9 = props.theme.success, _v$0 = props.theme.text, _v$1 = props.theme.textMuted, _v$10 = props.theme.success, _v$11 = props.theme.text, _v$12 = props.theme.textMuted, _v$13 = props.theme.success, _v$14 = props.theme.text, _v$15 = props.theme.textMuted;
473
506
  _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-system-metrics-tui",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "OpenCode TUI sidebar plugin for live system metrics",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -38,8 +38,8 @@
38
38
  },
39
39
  "devDependencies": {
40
40
  "@opencode-ai/plugin": "^1.18.29",
41
- "@types/node": "^22.10.5",
41
+ "@types/node": "^26.4.1",
42
42
  "tsx": "^4.19.2",
43
- "typescript": "^5.7.3"
43
+ "typescript": "^7.0.2"
44
44
  }
45
45
  }