@axium/sysadmin 0.3.0 → 0.3.2

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.
@@ -1,16 +1,16 @@
1
1
  import { session } from '@axium/client/cli/config';
2
2
  import { fetchAPI } from '@axium/client/requests';
3
3
  import { connect } from '@axium/client/socket';
4
- import { formatBytes, formatDuration } from '@axium/core';
4
+ import * as format from 'utilium/format';
5
5
  import { program } from 'commander';
6
6
  import * as io from 'ioium/node';
7
7
  import { styleText } from 'node:util';
8
8
  import './socket.js';
9
9
  function usage(info) {
10
- return styleText('blueBright', formatBytes(info.used)) + '/' + styleText('blueBright', formatBytes(info.total));
10
+ return styleText('blueBright', format.bytes(info.used)) + '/' + styleText('blueBright', format.bytes(info.total));
11
11
  }
12
12
  function drive(device) {
13
- return styleText('blueBright', formatBytes(device.size)) + (device.interface ? ' ' + styleText('dim', device.interface) : '');
13
+ return styleText('blueBright', format.bytes(device.size)) + (device.interface ? ' ' + styleText('dim', device.interface) : '');
14
14
  }
15
15
  const num = (value) => value === undefined ? styleText('red', '<unknown>') : styleText('blueBright', value.toString());
16
16
  const tab = ' ', tab2 = ' ';
@@ -48,7 +48,7 @@ function dumpInfo(system, info) {
48
48
  if (iface.connected)
49
49
  console.log(tab2, iface.connection ? 'Connected to ' + iface.connection : 'Connected', 'at', num(iface.speed), 'MBit/s');
50
50
  }
51
- console.log('Uptime:', formatDuration(uptime));
51
+ console.log('Uptime:', format.duration(uptime));
52
52
  for (const [key, value] of Object.entries(rest)) {
53
53
  console.log(key + ':', value);
54
54
  }
@@ -65,7 +65,7 @@ function gpus() {
65
65
  }
66
66
  return result;
67
67
  }
68
- /** PCIe generations by their per-lane transfer rate in GT/s, as reported by `current_link_speed`. */
68
+ /** PCIe generations by their per-lane transfer rate in GT/s, as reported by `max_link_speed`. */
69
69
  const pcieGenerations = {
70
70
  '2.5': '1.0',
71
71
  '5.0': '2.0',
@@ -79,6 +79,16 @@ const pcieGenerations = {
79
79
  function formatLinkRate(mbps) {
80
80
  return mbps >= 1000 ? `${(mbps / 1000).toFixed(1).replace(/\.0$/, '')} Gbps` : `${mbps} Mbps`;
81
81
  }
82
+ /** A PCIe `*_link_speed` value (`16.0 GT/s PCIe`) in GT/s, or Infinity when it is missing or unparseable. */
83
+ function linkRate(path) {
84
+ const rate = Number(read(path)?.split(' ')[0]);
85
+ return rate > 0 ? rate : Infinity;
86
+ }
87
+ /** A PCIe `*_link_width` value in lanes, or Infinity when it is missing or unparseable. */
88
+ function linkWidth(path) {
89
+ const width = Number(read(path));
90
+ return width > 0 ? width : Infinity;
91
+ }
82
92
  /** The SATA link speed of an `ataN` device directory, e.g. '6.0 Gbps'. */
83
93
  function sataSpeed(ata) {
84
94
  for (const link of list(ata)) {
@@ -108,13 +118,14 @@ function diskInterface(dev) {
108
118
  const speed = sataSpeed(dir);
109
119
  return speed ? `SATA ${speed}` : 'SATA';
110
120
  }
111
- // PCI(e) endpoints expose the negotiated link; `current_link_speed` is like `16.0 GT/s PCIe`.
112
- const link = read(`${dir}/current_link_speed`);
113
- if (link) {
114
- const rate = link.split(' ')[0];
115
- const generation = pcieGenerations[Number(rate).toFixed(1)];
116
- const width = read(`${dir}/current_link_width`);
117
- return `PCIe ${generation ?? `${rate} GT/s`}${width && width !== '0' ? ` x${width}` : ''}`;
121
+ if (fs.existsSync(`${dir}/max_link_speed`)) {
122
+ const parent = path.dirname(dir);
123
+ const rate = Math.min(linkRate(`${dir}/max_link_speed`), linkRate(`${parent}/max_link_speed`));
124
+ const width = Math.min(linkWidth(`${dir}/max_link_width`), linkWidth(`${parent}/max_link_width`));
125
+ if (Number.isFinite(rate)) {
126
+ const generation = pcieGenerations[rate.toFixed(1)];
127
+ return `PCIe ${generation ?? `${rate} GT/s`}${Number.isFinite(width) ? ` x${width}` : ''}`;
128
+ }
118
129
  }
119
130
  // USB devices (as opposed to their interfaces) carry the descriptor fields; `speed` is in Mbit/s.
120
131
  if (fs.existsSync(`${dir}/idVendor`)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/sysadmin",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "author": "James Prevett <axium@jamespre.dev>",
5
5
  "description": "System administration for Axium",
6
6
  "funding": {
@@ -41,7 +41,7 @@
41
41
  "@axium/server": ">=0.47.0",
42
42
  "@sveltejs/kit": "^2.27.3",
43
43
  "kysely": "^0.29.0",
44
- "utilium": "^3.0.0"
44
+ "utilium": "^3.8.0"
45
45
  },
46
46
  "dependencies": {
47
47
  "commander": "^15.0.0",
@@ -3,7 +3,7 @@
3
3
  import { Icon, NumberBar } from '@axium/client/components';
4
4
  import { connect } from '@axium/client/socket';
5
5
  import { toastStatus } from '@axium/client/toast';
6
- import { formatBytes, formatDuration } from '@axium/core';
6
+ import * as format from 'utilium/format';
7
7
  import { systemTypeIcons, type SystemInfo } from '@axium/sysadmin';
8
8
  import '@axium/sysadmin/common';
9
9
 
@@ -36,8 +36,8 @@
36
36
  }
37
37
 
38
38
  function usageText(used: bigint, total: bigint): string {
39
- if (used <= 0n) return formatBytes(total);
40
- return text('sysadmin.system.usage', { used: formatBytes(used), total: formatBytes(total) });
39
+ if (used <= 0n) return format.bytes(total);
40
+ return text('sysadmin.system.usage', { used: format.bytes(used), total: format.bytes(total) });
41
41
  }
42
42
 
43
43
  const socket = await connect();
@@ -184,7 +184,7 @@
184
184
  {disk.model}
185
185
  </span>
186
186
  <span class="subtle">
187
- {formatBytes(disk.size)}
187
+ {format.bytes(disk.size)}
188
188
  {#if disk.interface}<span class="dot">·</span>{disk.interface}{/if}
189
189
  </span>
190
190
  </div>
@@ -197,7 +197,7 @@
197
197
  <span class="mount">{disk.model}</span>
198
198
  <span class="tags">
199
199
  <span class="subtle">
200
- {formatBytes(disk.size)}
200
+ {format.bytes(disk.size)}
201
201
  {#if disk.interface}<span class="dot">·</span>{disk.interface}{/if}
202
202
  </span>
203
203
  <span class="tag unused">{text('sysadmin.system.storage_unused')}</span>
@@ -248,7 +248,7 @@
248
248
  <dt>{text('sysadmin.system.arch')}</dt>
249
249
  <dd>{info.arch} <span class="subtle">({info.machine})</span></dd>
250
250
  <dt>{text('sysadmin.system.uptime')}</dt>
251
- <dd>{formatDuration(info.uptime)}</dd>
251
+ <dd>{format.duration(info.uptime)}</dd>
252
252
  </dl>
253
253
  </section>
254
254
  {/if}