opencode-system-metrics-tui 0.1.11 → 0.1.12

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.
Files changed (3) hide show
  1. package/README.md +12 -10
  2. package/dist/tui.js +252 -46
  3. package/package.json +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.11 --force
6
+ opencode plugin -g opencode-system-metrics-tui@0.1.12 --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:
@@ -94,7 +94,7 @@ npm publish --access public
94
94
  En otro equipo:
95
95
 
96
96
  ```bash
97
- opencode plugin opencode-system-metrics-tui@0.1.11
97
+ opencode plugin opencode-system-metrics-tui@0.1.12
98
98
  ```
99
99
 
100
100
  El paquete exporta tanto la raíz (`opencode-system-metrics-tui`) como `./tui`; ambas rutas cargan el mismo bundle TUI.
@@ -104,8 +104,8 @@ El instalador de OpenCode configura el plugin TUI automáticamente. Reinicia Ope
104
104
  Publicar en npm e instalar en OpenCode son pasos distintos:
105
105
 
106
106
  - `npm publish --access public` publica el paquete en npm.
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.
107
+ - `opencode plugin opencode-system-metrics-tui@0.1.12` lo instala solo en el proyecto actual.
108
+ - `opencode plugin -g opencode-system-metrics-tui@0.1.12 --force` lo instala globalmente para todos los proyectos.
109
109
 
110
110
  ### Verificación
111
111
 
@@ -134,6 +134,8 @@ npm run build
134
134
  - Windows uses Unicode icons by default (installed-font detection does not change selection); Linux/macOS use Nerd Font only when installed and retain Unicode fallback.
135
135
  - On Windows, visible Unicode icons are used by default because OpenCode cannot detect the terminal's active font.
136
136
  - Supports Linux, macOS, and Windows when the operating system exposes the metrics.
137
+ - CPU and RAM use native, read-only paths without subprocesses during normal operation: Linux reads `/proc/stat` and `/proc/meminfo`; Windows uses `GetSystemTimes` and `GlobalMemoryStatusEx` through the lazy Koffi integration; macOS uses Mach host statistics and `hw.memsize` on both Intel and Apple Silicon. If native loading or a read fails, the existing `systeminformation` path is used with the existing timeout and cache protections.
138
+ - Native CPU percentages are deltas between consecutive samples; the first sample is intentionally unavailable. Counter resets, malformed data, and API failures fall back safely. Apple Silicon retains unified-memory semantics and does not treat system RAM as discrete VRAM.
137
139
  - 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.
138
140
  - On Windows, CPU temperature requires LibreHardwareMonitor running as administrator with **Remote Web Server** enabled at `http://127.0.0.1:8085`.
139
141
  - 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.
@@ -190,7 +192,7 @@ npm publish --access public
190
192
  On another machine:
191
193
 
192
194
  ```bash
193
- opencode plugin opencode-system-metrics-tui@0.1.11
195
+ opencode plugin opencode-system-metrics-tui@0.1.12
194
196
  ```
195
197
 
196
198
  The package exports both the root (`opencode-system-metrics-tui`) and `./tui`; both paths load the same TUI bundle.
@@ -200,8 +202,8 @@ The OpenCode installer configures the TUI plugin automatically. Restart OpenCode
200
202
  Publishing to npm and installing in OpenCode are separate steps:
201
203
 
202
204
  - `npm publish --access public` publishes the package to npm.
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.
205
+ - `opencode plugin opencode-system-metrics-tui@0.1.12` installs it for the current project only.
206
+ - `opencode plugin -g opencode-system-metrics-tui@0.1.12 --force` installs it globally for all projects.
205
207
 
206
208
  ### Verification
207
209
 
@@ -285,7 +287,7 @@ npm publish --access public
285
287
  Em outro computador:
286
288
 
287
289
  ```bash
288
- opencode plugin opencode-system-metrics-tui@0.1.11
290
+ opencode plugin opencode-system-metrics-tui@0.1.12
289
291
  ```
290
292
 
291
293
  O pacote exporta tanto a raiz (`opencode-system-metrics-tui`) quanto `./tui`; os dois caminhos carregam o mesmo bundle TUI.
@@ -295,8 +297,8 @@ O instalador do OpenCode configura o plugin TUI automaticamente. Reinicie o Open
295
297
  Publicar no npm e instalar no OpenCode são etapas diferentes:
296
298
 
297
299
  - `npm publish --access public` publica o pacote no npm.
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.
300
+ - `opencode plugin opencode-system-metrics-tui@0.1.12` instala o plugin apenas no projeto atual.
301
+ - `opencode plugin -g opencode-system-metrics-tui@0.1.12 --force` instala o plugin globalmente para todos os projetos.
300
302
 
301
303
  ### Verificação
302
304
 
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 { createMemo, createSignal, onCleanup, onMount } from "solid-js";
9
+ import { Show, createMemo, createSignal, onCleanup, onMount } from "solid-js";
10
10
  import { TextAttributes } from "@opentui/core";
11
11
 
12
12
  // src/format.ts
@@ -160,6 +160,189 @@ async function readWindowsNetworkCounters() {
160
160
  return mapWindowsNetworkRows((await nativeReader)());
161
161
  }
162
162
 
163
+ // src/native-metrics.ts
164
+ import { readFile } from "node:fs/promises";
165
+ function parseLinuxCpuCounters(stat) {
166
+ const line = stat.split(/\r?\n/).find((item) => /^cpu(?:\s|$)/.test(item));
167
+ if (line === undefined)
168
+ return;
169
+ const fields = line.trim().split(/\s+/).slice(1);
170
+ if (fields.length < 4)
171
+ return;
172
+ const values = fields.map((value) => {
173
+ try {
174
+ const parsed = BigInt(value);
175
+ return parsed >= 0n ? parsed : undefined;
176
+ } catch {
177
+ return;
178
+ }
179
+ });
180
+ if (values.some((value) => value === undefined))
181
+ return;
182
+ const numbers = values;
183
+ return { total: numbers.reduce((sum, value) => sum + value, 0n), idle: numbers[3] + (numbers[4] ?? 0n) };
184
+ }
185
+ function cpuPercentFromCounters(current, previous) {
186
+ if (previous === undefined || current.total < previous.total || current.idle < previous.idle)
187
+ return;
188
+ const totalDelta = current.total - previous.total;
189
+ const idleDelta = current.idle - previous.idle;
190
+ if (totalDelta <= 0n || idleDelta > totalDelta)
191
+ return;
192
+ return Number((totalDelta - idleDelta) * 10000n / totalDelta) / 100;
193
+ }
194
+ function parseLinuxMemoryInfo(meminfo) {
195
+ const values = new Map;
196
+ for (const line of meminfo.split(/\r?\n/)) {
197
+ const match = /^(MemTotal|MemAvailable|MemFree|Buffers|Cached):\s+(\d+)(?:\s+kB)?\s*$/.exec(line);
198
+ if (match !== null)
199
+ values.set(match[1], Number(match[2]) * 1024);
200
+ }
201
+ const total = values.get("MemTotal");
202
+ const hasAvailable = values.has("MemAvailable") || values.has("MemFree") || values.has("Buffers") || values.has("Cached");
203
+ const available = values.get("MemAvailable") ?? (values.get("MemFree") ?? 0) + (values.get("Buffers") ?? 0) + (values.get("Cached") ?? 0);
204
+ if (total === undefined || !hasAvailable || !Number.isSafeInteger(total) || !Number.isSafeInteger(available) || total <= 0 || available < 0)
205
+ return;
206
+ return { totalBytes: total, availableBytes: Math.min(total, available) };
207
+ }
208
+ function mapMemoryBytes(totalBytes, availableBytes) {
209
+ if (!Number.isSafeInteger(totalBytes) || !Number.isSafeInteger(availableBytes) || totalBytes <= 0 || availableBytes < 0)
210
+ return;
211
+ return { memoryTotalBytes: totalBytes, memoryAvailableBytes: Math.min(totalBytes, availableBytes) };
212
+ }
213
+ var reader;
214
+ async function readNativeMetrics() {
215
+ reader ??= (async () => {
216
+ if (process.platform === "linux")
217
+ return createLinuxReader();
218
+ if (process.platform === "win32")
219
+ return createWindowsReader();
220
+ if (process.platform === "darwin")
221
+ return createMacReader();
222
+ throw new Error(`Native CPU/RAM metrics are unsupported on ${process.platform}`);
223
+ })();
224
+ return (await reader)();
225
+ }
226
+ function createLinuxReader() {
227
+ let previous;
228
+ return async () => {
229
+ const [stat, meminfo] = await Promise.all([readFile("/proc/stat", "utf8"), readFile("/proc/meminfo", "utf8")]);
230
+ const counters = parseLinuxCpuCounters(stat);
231
+ const memory = parseLinuxMemoryInfo(meminfo);
232
+ if (counters === undefined || memory === undefined)
233
+ throw new Error("Malformed Linux CPU/RAM data");
234
+ const cpuPercent = cpuPercentFromCounters(counters, previous);
235
+ previous = cpuPercent === undefined && previous !== undefined ? undefined : counters;
236
+ return { cpuPercent, memoryTotalBytes: memory.totalBytes, memoryAvailableBytes: memory.availableBytes };
237
+ };
238
+ }
239
+ async function createWindowsReader() {
240
+ const loaded = await import("koffi");
241
+ const koffi = loaded.default ?? loaded;
242
+ koffi.struct("FILETIME", { low: "uint32", high: "uint32" });
243
+ const memoryStatus = koffi.struct("MEMORYSTATUSEX", {
244
+ length: "uint32",
245
+ memoryLoad: "uint32",
246
+ total: "uint64",
247
+ available: "uint64",
248
+ pageFile: "uint64",
249
+ availablePageFile: "uint64",
250
+ virtual: "uint64",
251
+ availableVirtual: "uint64",
252
+ availableExtended: "uint64"
253
+ });
254
+ const kernel32 = koffi.load("kernel32.dll");
255
+ const getSystemTimes = kernel32.func("int __stdcall GetSystemTimes(_Out_ FILETIME *idle, _Out_ FILETIME *kernel, _Out_ FILETIME *user)");
256
+ const globalMemoryStatusEx = kernel32.func("int __stdcall GlobalMemoryStatusEx(_Inout_ MEMORYSTATUSEX *status)");
257
+ let previous;
258
+ return async () => {
259
+ const idle = {};
260
+ const kernel = {};
261
+ const user = {};
262
+ if (!getSystemTimes(idle, kernel, user))
263
+ throw new Error("GetSystemTimes failed");
264
+ const toUint64 = (value) => BigInt(value.low ?? 0) + (BigInt(value.high ?? 0) << 32n);
265
+ const counters = { total: toUint64(kernel) + toUint64(user), idle: toUint64(idle) };
266
+ const cpuPercent = cpuPercentFromCounters(counters, previous);
267
+ previous = cpuPercent === undefined && previous !== undefined ? undefined : counters;
268
+ const status = { length: koffi.sizeof(memoryStatus) };
269
+ if (!globalMemoryStatusEx(status))
270
+ throw new Error("GlobalMemoryStatusEx failed");
271
+ const memory = mapMemoryBytes(Number(status.total ?? 0n), Number(status.available ?? 0n));
272
+ if (memory === undefined)
273
+ throw new Error("Malformed Windows RAM data");
274
+ return { cpuPercent, ...memory };
275
+ };
276
+ }
277
+ async function createMacReader() {
278
+ const loaded = await import("koffi");
279
+ const koffi = loaded.default ?? loaded;
280
+ const vmStatistics = koffi.struct("vm_statistics64", {
281
+ free_count: "uint32",
282
+ active_count: "uint32",
283
+ inactive_count: "uint32",
284
+ wire_count: "uint32",
285
+ zero_fill_count: "uint32",
286
+ reactivations: "uint32",
287
+ pageins: "uint32",
288
+ pageouts: "uint32",
289
+ faults: "uint32",
290
+ cow_faults: "uint32",
291
+ lookups: "uint32",
292
+ hits: "uint32",
293
+ purgeable_count: "uint32",
294
+ speculative_count: "uint32",
295
+ decompressions: "uint32",
296
+ compressions: "uint32",
297
+ swapins: "uint32",
298
+ swapouts: "uint32",
299
+ compressor_page_count: "uint32",
300
+ throttled_count: "uint32",
301
+ external_page_count: "uint32",
302
+ internal_page_count: "uint32",
303
+ total_uncompressed_pages_in_compressor: "uint32"
304
+ });
305
+ const cpuLoad = koffi.struct("host_cpu_load_info", { user: "uint32", system: "uint32", idle: "uint32", nice: "uint32" });
306
+ const libc = koffi.load("libSystem.B.dylib");
307
+ const sysctlbyname = libc.func("int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen)");
308
+ const machHostSelf = libc.func("uint32 mach_host_self()");
309
+ const hostStatistics64 = libc.func("int host_statistics64(uint32 host, int flavor, _Out_ vm_statistics64 *stats, _Inout_ uint32_t *count)");
310
+ const hostCpuLoad = libc.func("int host_statistics(uint32 host, int flavor, _Out_ host_cpu_load_info *load, _Inout_ uint32_t *count)");
311
+ const readUint64Sysctl = (name) => {
312
+ const output = koffi.alloc("uint64", 1);
313
+ const length = [8];
314
+ if (sysctlbyname(name, output, length, null, 0) !== 0)
315
+ throw new Error(`sysctlbyname failed: ${name}`);
316
+ return Number(koffi.decode(output, "uint64"));
317
+ };
318
+ const totalBytes = readUint64Sysctl("hw.memsize");
319
+ const pageSize = readUint64Sysctl("hw.pagesize");
320
+ if (!Number.isSafeInteger(totalBytes) || !Number.isSafeInteger(pageSize) || pageSize <= 0)
321
+ throw new Error("Malformed macOS memory data");
322
+ let previous;
323
+ return async () => {
324
+ const load = {};
325
+ const loadCount = [4];
326
+ if (hostCpuLoad(machHostSelf(), 3, load, loadCount) !== 0)
327
+ throw new Error("host_statistics failed");
328
+ const counters = {
329
+ total: BigInt(load.user ?? 0) + BigInt(load.system ?? 0) + BigInt(load.idle ?? 0) + BigInt(load.nice ?? 0),
330
+ idle: BigInt(load.idle ?? 0)
331
+ };
332
+ const cpuPercent = cpuPercentFromCounters(counters, previous);
333
+ previous = cpuPercent === undefined && previous !== undefined ? undefined : counters;
334
+ const stats = {};
335
+ const count = [38];
336
+ if (hostStatistics64(machHostSelf(), 4, stats, count) !== 0)
337
+ throw new Error("host_statistics64 failed");
338
+ const availablePages = (stats.free_count ?? 0) + (stats.inactive_count ?? 0) + (stats.purgeable_count ?? 0) + (stats.speculative_count ?? 0);
339
+ const memory = mapMemoryBytes(totalBytes, availablePages * pageSize);
340
+ if (memory === undefined)
341
+ throw new Error("Malformed macOS RAM data");
342
+ return { cpuPercent, ...memory };
343
+ };
344
+ }
345
+
163
346
  // src/metrics.ts
164
347
  var execFileAsync = promisify(execFile);
165
348
  var DEFAULT_METRIC_TIMEOUT_MS = 1500;
@@ -451,21 +634,31 @@ async function readWindowsCpuTemperature() {
451
634
  return value === undefined ? undefined : { main: value };
452
635
  }
453
636
  async function readMetrics() {
454
- const [load, memory, hardwareArchitecture] = await Promise.allSettled([
455
- withTimeout(si.currentLoad(), DEFAULT_METRIC_TIMEOUT_MS),
456
- withTimeout(si.mem(), isWindows ? WINDOWS_MEMORY_TIMEOUT_MS : DEFAULT_METRIC_TIMEOUT_MS),
637
+ const [native, hardwareArchitecture] = await Promise.allSettled([
638
+ withTimeout(readNativeMetrics(), isWindows ? WINDOWS_MEMORY_TIMEOUT_MS : DEFAULT_METRIC_TIMEOUT_MS),
457
639
  readMacHardwareArchitecture()
458
640
  ]);
641
+ let cpuPercent = native.status === "fulfilled" ? finite(native.value.cpuPercent) : null;
642
+ let memoryTotalBytes = native.status === "fulfilled" ? finite(native.value.memoryTotalBytes) : null;
643
+ let memoryAvailableBytes = native.status === "fulfilled" ? finite(native.value.memoryAvailableBytes) : null;
644
+ let fallbackMemoryUsedBytes = null;
645
+ if (native.status !== "fulfilled") {
646
+ const [load, memory] = await Promise.allSettled([
647
+ withTimeout(si.currentLoad(), DEFAULT_METRIC_TIMEOUT_MS),
648
+ withTimeout(si.mem(), isWindows ? WINDOWS_MEMORY_TIMEOUT_MS : DEFAULT_METRIC_TIMEOUT_MS)
649
+ ]);
650
+ cpuPercent = load.status === "fulfilled" ? finite(load.value.currentLoad) : null;
651
+ memoryTotalBytes = memory.status === "fulfilled" ? finite(memory.value.total) : null;
652
+ memoryAvailableBytes = memory.status === "fulfilled" ? finite(memory.value.available) : null;
653
+ fallbackMemoryUsedBytes = memoryTotalBytes !== null && memoryAvailableBytes !== null ? Math.max(0, memoryTotalBytes - memoryAvailableBytes) : memory.status === "fulfilled" ? finite(memory.value.used) : null;
654
+ }
459
655
  const [temperature, graphics, network, mac] = await Promise.allSettled([
460
656
  readCachedMetric(cachedCpuTemperature, isWindows ? readWindowsCpuTemperature : () => si.cpuTemperature(), TEMPERATURE_CACHE_MS, Date.now(), TEMPERATURE_CACHE_MS, 2500),
461
657
  readCachedMetric(cachedGraphics, () => si.graphics(), SLOW_METRIC_CACHE_MS, Date.now(), SLOW_METRIC_CACHE_MS, 2500),
462
658
  readCachedMetric(cachedNetwork, isWindows ? readWindowsNetworkMetrics : () => si.networkStats("*"), isWindows ? NETWORK_CACHE_MS : 2000, Date.now(), OPTIONAL_SOURCE_BACKOFF_MS, isWindows ? WINDOWS_NETWORK_OUTER_TIMEOUT_MS : DEFAULT_METRIC_TIMEOUT_MS),
463
659
  isMac ? readCachedMetric(cachedMacMetrics, () => readMacMetrics(), SLOW_METRIC_CACHE_MS, Date.now(), OPTIONAL_SOURCE_BACKOFF_MS, MAC_METRIC_TIMEOUT_MS) : Promise.resolve(undefined)
464
660
  ]);
465
- const cpuPercent = load.status === "fulfilled" ? finite(load.value.currentLoad) : null;
466
- const memoryTotalBytes = memory.status === "fulfilled" ? finite(memory.value.total) : null;
467
- const memoryAvailableBytes = memory.status === "fulfilled" ? finite(memory.value.available) : null;
468
- const memoryUsedBytes = memoryTotalBytes !== null && memoryAvailableBytes !== null ? Math.max(0, memoryTotalBytes - memoryAvailableBytes) : memory.status === "fulfilled" ? finite(memory.value.used) : null;
661
+ const memoryUsedBytes = fallbackMemoryUsedBytes ?? (memoryTotalBytes !== null && memoryAvailableBytes !== null ? Math.max(0, memoryTotalBytes - memoryAvailableBytes) : null);
469
662
  const memoryPercent = memoryUsedBytes !== null && memoryTotalBytes !== null && memoryTotalBytes > 0 ? memoryUsedBytes / memoryTotalBytes * 100 : null;
470
663
  const gpu = selectGpuMetrics(graphics.status === "fulfilled" ? graphics.value : undefined);
471
664
  const macMetrics = mac.status === "fulfilled" ? mac.value : undefined;
@@ -657,12 +850,11 @@ function MetricsPanel(props) {
657
850
  };
658
851
  });
659
852
  return (() => {
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(` ↑ `);
853
+ 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$33 = _$createElement("box"), _el$34 = _$createElement("text"), _el$35 = _$createElement("text"), _el$37 = _$createElement("text"), _el$38 = _$createTextNode(`↓ `), _el$39 = _$createTextNode(` ↑ `);
661
854
  _$insertNode(_el$, _el$2);
662
855
  _$insertNode(_el$, _el$4);
663
856
  _$insertNode(_el$, _el$1);
664
857
  _$insertNode(_el$, _el$17);
665
- _$insertNode(_el$, _el$24);
666
858
  _$insertNode(_el$, _el$33);
667
859
  _$setProp(_el$, "flexDirection", "column");
668
860
  _$setProp(_el$, "paddingLeft", 0);
@@ -704,20 +896,40 @@ function MetricsPanel(props) {
704
896
  _$insert(_el$21, () => formatPercent(metricsState.sharedMetrics().gpuPercent), _el$22);
705
897
  _$insert(_el$21, () => icons.thermometer, _el$23);
706
898
  _$insert(_el$21, () => formatTemperature(metricsState.sharedMetrics().gpuTemperatureCelsius), null);
707
- _$insertNode(_el$24, _el$25);
708
- _$insertNode(_el$24, _el$26);
709
- _$insertNode(_el$24, _el$29);
710
- _$setProp(_el$24, "flexDirection", "row");
711
- _$insert(_el$25, () => gpuMemory().icon);
712
- _$insertNode(_el$26, _el$27);
713
- _$insertNode(_el$26, _el$28);
714
- _$insert(_el$26, () => gpuMemory().label, _el$28);
715
- _$insertNode(_el$29, _el$30);
716
- _$insertNode(_el$29, _el$31);
717
- _$insertNode(_el$29, _el$32);
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);
899
+ _$insert(_el$, _$createComponent(Show, {
900
+ get when() {
901
+ return metricsState.sharedMetrics().gpuMemoryIsUnified !== true;
902
+ },
903
+ get children() {
904
+ var _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(`)`);
905
+ _$insertNode(_el$24, _el$25);
906
+ _$insertNode(_el$24, _el$26);
907
+ _$insertNode(_el$24, _el$29);
908
+ _$setProp(_el$24, "flexDirection", "row");
909
+ _$insert(_el$25, () => gpuMemory().icon);
910
+ _$insertNode(_el$26, _el$27);
911
+ _$insertNode(_el$26, _el$28);
912
+ _$insert(_el$26, () => gpuMemory().label, _el$28);
913
+ _$insertNode(_el$29, _el$30);
914
+ _$insertNode(_el$29, _el$31);
915
+ _$insertNode(_el$29, _el$32);
916
+ _$insert(_el$29, () => formatGiB(gpuMemory().usedBytes), _el$30);
917
+ _$insert(_el$29, () => formatGiB(gpuMemory().totalBytes), _el$31);
918
+ _$insert(_el$29, () => formatPercent(gpuMemory().percent), _el$32);
919
+ _$effect((_p$) => {
920
+ var _v$ = props.theme.success, _v$2 = props.theme.text, _v$3 = props.theme.textMuted;
921
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$25, "fg", _v$, _p$.e));
922
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$26, "fg", _v$2, _p$.t));
923
+ _v$3 !== _p$.a && (_p$.a = _$setProp(_el$29, "fg", _v$3, _p$.a));
924
+ return _p$;
925
+ }, {
926
+ e: undefined,
927
+ t: undefined,
928
+ a: undefined
929
+ });
930
+ return _el$24;
931
+ }
932
+ }), _el$33);
721
933
  _$insertNode(_el$33, _el$34);
722
934
  _$insertNode(_el$33, _el$35);
723
935
  _$insertNode(_el$33, _el$37);
@@ -729,24 +941,21 @@ function MetricsPanel(props) {
729
941
  _$insert(_el$37, () => formatRate(metricsState.sharedMetrics().downloadBytesPerSecond), _el$39);
730
942
  _$insert(_el$37, () => formatRate(metricsState.sharedMetrics().uploadBytesPerSecond), null);
731
943
  _$effect((_p$) => {
732
- 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;
733
- _v$ !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$, _p$.e));
734
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "attributes", _v$2, _p$.t));
735
- _v$3 !== _p$.a && (_p$.a = _$setProp(_el$5, "fg", _v$3, _p$.a));
736
- _v$4 !== _p$.o && (_p$.o = _$setProp(_el$6, "fg", _v$4, _p$.o));
737
- _v$5 !== _p$.i && (_p$.i = _$setProp(_el$8, "fg", _v$5, _p$.i));
738
- _v$6 !== _p$.n && (_p$.n = _$setProp(_el$10, "fg", _v$6, _p$.n));
739
- _v$7 !== _p$.s && (_p$.s = _$setProp(_el$11, "fg", _v$7, _p$.s));
740
- _v$8 !== _p$.h && (_p$.h = _$setProp(_el$13, "fg", _v$8, _p$.h));
741
- _v$9 !== _p$.r && (_p$.r = _$setProp(_el$18, "fg", _v$9, _p$.r));
742
- _v$0 !== _p$.d && (_p$.d = _$setProp(_el$19, "fg", _v$0, _p$.d));
743
- _v$1 !== _p$.l && (_p$.l = _$setProp(_el$21, "fg", _v$1, _p$.l));
744
- _v$10 !== _p$.u && (_p$.u = _$setProp(_el$25, "fg", _v$10, _p$.u));
745
- _v$11 !== _p$.c && (_p$.c = _$setProp(_el$26, "fg", _v$11, _p$.c));
746
- _v$12 !== _p$.w && (_p$.w = _$setProp(_el$29, "fg", _v$12, _p$.w));
747
- _v$13 !== _p$.m && (_p$.m = _$setProp(_el$34, "fg", _v$13, _p$.m));
748
- _v$14 !== _p$.f && (_p$.f = _$setProp(_el$35, "fg", _v$14, _p$.f));
749
- _v$15 !== _p$.y && (_p$.y = _$setProp(_el$37, "fg", _v$15, _p$.y));
944
+ var _v$4 = props.theme.text, _v$5 = TextAttributes.BOLD, _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;
945
+ _v$4 !== _p$.e && (_p$.e = _$setProp(_el$2, "fg", _v$4, _p$.e));
946
+ _v$5 !== _p$.t && (_p$.t = _$setProp(_el$2, "attributes", _v$5, _p$.t));
947
+ _v$6 !== _p$.a && (_p$.a = _$setProp(_el$5, "fg", _v$6, _p$.a));
948
+ _v$7 !== _p$.o && (_p$.o = _$setProp(_el$6, "fg", _v$7, _p$.o));
949
+ _v$8 !== _p$.i && (_p$.i = _$setProp(_el$8, "fg", _v$8, _p$.i));
950
+ _v$9 !== _p$.n && (_p$.n = _$setProp(_el$10, "fg", _v$9, _p$.n));
951
+ _v$0 !== _p$.s && (_p$.s = _$setProp(_el$11, "fg", _v$0, _p$.s));
952
+ _v$1 !== _p$.h && (_p$.h = _$setProp(_el$13, "fg", _v$1, _p$.h));
953
+ _v$10 !== _p$.r && (_p$.r = _$setProp(_el$18, "fg", _v$10, _p$.r));
954
+ _v$11 !== _p$.d && (_p$.d = _$setProp(_el$19, "fg", _v$11, _p$.d));
955
+ _v$12 !== _p$.l && (_p$.l = _$setProp(_el$21, "fg", _v$12, _p$.l));
956
+ _v$13 !== _p$.u && (_p$.u = _$setProp(_el$34, "fg", _v$13, _p$.u));
957
+ _v$14 !== _p$.c && (_p$.c = _$setProp(_el$35, "fg", _v$14, _p$.c));
958
+ _v$15 !== _p$.w && (_p$.w = _$setProp(_el$37, "fg", _v$15, _p$.w));
750
959
  return _p$;
751
960
  }, {
752
961
  e: undefined,
@@ -762,10 +971,7 @@ function MetricsPanel(props) {
762
971
  l: undefined,
763
972
  u: undefined,
764
973
  c: undefined,
765
- w: undefined,
766
- m: undefined,
767
- f: undefined,
768
- y: undefined
974
+ w: undefined
769
975
  });
770
976
  return _el$;
771
977
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-system-metrics-tui",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "OpenCode TUI sidebar plugin for live system metrics",
5
5
  "license": "MIT",
6
6
  "type": "module",