rigscope 0.1.2 → 0.1.4
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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +2 -2
- package/.next/build-manifest.json +2 -2
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/administration/page_client-reference-manifest.js +1 -1
- package/.next/server/app/administration.html +1 -1
- package/.next/server/app/administration.rsc +2 -2
- package/.next/server/app/administration.segments/_full.segment.rsc +2 -2
- package/.next/server/app/administration.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/alerts/page_client-reference-manifest.js +1 -1
- package/.next/server/app/alerts.html +1 -1
- package/.next/server/app/alerts.rsc +2 -2
- package/.next/server/app/alerts.segments/_full.segment.rsc +2 -2
- package/.next/server/app/alerts.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/connections/page_client-reference-manifest.js +1 -1
- package/.next/server/app/connections.html +1 -1
- package/.next/server/app/connections.rsc +2 -2
- package/.next/server/app/connections.segments/_full.segment.rsc +2 -2
- package/.next/server/app/connections.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/history/page.js +1 -1
- package/.next/server/app/history/page_client-reference-manifest.js +1 -1
- package/.next/server/app/history.html +1 -1
- package/.next/server/app/history.rsc +4 -4
- package/.next/server/app/history.segments/_full.segment.rsc +4 -4
- package/.next/server/app/history.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +2 -2
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +2 -2
- package/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/machines/[machineId]/page.js +1 -1
- package/.next/server/app/machines/[machineId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/processes/page.js +1 -1
- package/.next/server/app/processes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/processes.html +1 -1
- package/.next/server/app/processes.rsc +3 -3
- package/.next/server/app/processes.segments/_full.segment.rsc +3 -3
- package/.next/server/app/processes.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +3 -3
- package/.next/server/app-paths-manifest.json +2 -2
- package/.next/server/chunks/161.js +1 -1
- package/.next/server/chunks/168.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/408-29f55984738967db.js +1 -0
- package/.next/static/chunks/939-514e554087419c71.js +1 -0
- package/.next/static/chunks/app/history/{page-22be927a4c3a9c76.js → page-69ea64476ee5db85.js} +1 -1
- package/.next/static/chunks/app/machines/[machineId]/page-1a25a267563c18c0.js +1 -0
- package/.next/static/chunks/app/processes/{page-e471ed23a1d5632f.js → page-0e98a4a64e829c5f.js} +1 -1
- package/ARCHITECTURE.md +30 -4
- package/CHANGELOG.md +53 -2
- package/README.md +2 -0
- package/dist/cli.cjs +3575 -2555
- package/dist/collector.cjs +155 -232
- package/dist/hub.cjs +5 -18
- package/dist/ops.cjs +158 -31
- package/dist/system.cjs +869 -450
- package/docs/bottlenecks.md +4 -6
- package/docs/configuration.md +2 -0
- package/docs/installation.md +107 -23
- package/docs/operations.md +44 -22
- package/docs/releasing.md +21 -17
- package/docs/system-installation.md +11 -2
- package/package.json +1 -2
- package/.next/static/chunks/408-4fe7147e38981ee1.js +0 -1
- package/.next/static/chunks/939-2600d7c8e583d5ef.js +0 -1
- package/.next/static/chunks/app/machines/[machineId]/page-916ee73de5eb067d.js +0 -1
- /package/.next/static/{npHoP6NSY976Yaye-xi86 → -mNveXe-cHv8irQe97wI_}/_buildManifest.js +0 -0
- /package/.next/static/{npHoP6NSY976Yaye-xi86 → -mNveXe-cHv8irQe97wI_}/_ssgManifest.js +0 -0
package/docs/bottlenecks.md
CHANGED
|
@@ -38,12 +38,10 @@ counter near its ceiling. Monitoring continues when an optional sensor fails.
|
|
|
38
38
|
The new fields belong to the existing CPU, memory and disks sharing families.
|
|
39
39
|
Withholding a family withholds its bottleneck fields for that destination too.
|
|
40
40
|
|
|
41
|
-
Enhanced fields are
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
see enhanced readings; an independent older destination continues receiving its
|
|
46
|
-
existing metrics. Projection affects transmission, not the durable outbox record.
|
|
41
|
+
Enhanced fields are part of the canonical metrics contract and follow the
|
|
42
|
+
destination's sharing policy for live and replayed records. There is no
|
|
43
|
+
old-peer negotiation or payload projection. Update the hub and collector
|
|
44
|
+
together when replacing an unfinished installation.
|
|
47
45
|
|
|
48
46
|
Kernel references: [PSI](https://docs.kernel.org/accounting/psi.html),
|
|
49
47
|
[powercap](https://docs.kernel.org/power/powercap/powercap.html), and
|
package/docs/configuration.md
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
For an installation made with `rigscope install`, use `rigscope config` to find
|
|
4
4
|
its private settings. See [Hub configuration](installation.md#hub-configuration)
|
|
5
5
|
and [Remote access](installation.md#access-from-another-computer) for managed setup.
|
|
6
|
+
The private `config.json` has one canonical shape: it has no version field, and
|
|
7
|
+
its required `components` object records hub and collector enablement.
|
|
6
8
|
|
|
7
9
|
The environment variables below apply to source development and services that
|
|
8
10
|
run the hub or collector directly. Setting them in your shell does not change
|
package/docs/installation.md
CHANGED
|
@@ -27,7 +27,7 @@ install or source checkout is needed. The launcher and services use the installe
|
|
|
27
27
|
runtime, so removing the npx cache does not break them.
|
|
28
28
|
|
|
29
29
|
Releases are on [npm](https://www.npmjs.com/package/rigscope). `@latest` selects
|
|
30
|
-
the current stable release; replace it with `@0.1.
|
|
30
|
+
the current stable release; replace it with `@0.1.4` to select that exact version.
|
|
31
31
|
|
|
32
32
|
### Installation options
|
|
33
33
|
|
|
@@ -53,7 +53,7 @@ For a downloaded package or one built from source, run from the directory
|
|
|
53
53
|
containing the archive, or give its absolute path:
|
|
54
54
|
|
|
55
55
|
```sh
|
|
56
|
-
npx --yes --package ./rigscope-0.1.
|
|
56
|
+
npx --yes --package ./rigscope-0.1.4.tgz rigscope install --boot
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
The same installation options apply. npm still needs registry access or cached
|
|
@@ -71,15 +71,61 @@ Run only the command for the task you want:
|
|
|
71
71
|
| Stop local collection | `rigscope stop collector` |
|
|
72
72
|
| Follow logs | `rigscope logs --follow` |
|
|
73
73
|
| Check configuration, services and sensor access | `rigscope doctor` |
|
|
74
|
-
| Remove
|
|
74
|
+
| Remove the installation and all its data | `rigscope uninstall` |
|
|
75
|
+
| Remove services and runtime, keeping saved data | `rigscope uninstall --keep-data` |
|
|
75
76
|
|
|
76
77
|
`start` is safe to repeat. `logs` shows the last 100 journal lines by default.
|
|
77
78
|
`enable` and `disable` control the hub and collector independently; the initial
|
|
78
79
|
role is a preset. Use `rigscope enable collector` to add local collection to a
|
|
79
80
|
hub-only installation.
|
|
80
81
|
|
|
81
|
-
`uninstall`
|
|
82
|
-
|
|
82
|
+
`uninstall` permanently deletes the selected user installation, including
|
|
83
|
+
accounts, history, collector credentials, pending samples and backups. It stops
|
|
84
|
+
owned services and foreground runtimes and never restarts them. `--purge` remains
|
|
85
|
+
an explicit alias for this default.
|
|
86
|
+
|
|
87
|
+
To keep saved data for a later reinstall, opt in:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
rigscope uninstall --keep-data
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If the launcher is already gone, use the package entry point:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
npx --yes rigscope@latest uninstall
|
|
97
|
+
npx --yes rigscope@latest install --role collector --boot
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Pass `--state-dir PATH` to select a separate installation. Reinstalling after
|
|
101
|
+
`uninstall --keep-data` reuses saved settings and the existing password. This
|
|
102
|
+
retention applies to canonical installations; upgrading a pre-canonical format
|
|
103
|
+
resets configuration and history, so back up the state directory first.
|
|
104
|
+
|
|
105
|
+
### Changes while running
|
|
106
|
+
|
|
107
|
+
Commands that need exclusive access detect the selected installation's running
|
|
108
|
+
services and foreground runtimes and ask before stopping them. After a successful
|
|
109
|
+
change, previously running components resume automatically. Uninstall never
|
|
110
|
+
restarts anything.
|
|
111
|
+
|
|
112
|
+
Use `--yes` to approve stopping without a prompt, and `--no-restart` to leave the
|
|
113
|
+
installation stopped after a change. In scripts, pass these flags to Rigscope:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
npx --yes rigscope@latest configure --port 8086 --yes --no-restart
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The first `--yes` belongs to npm; the second approves Rigscope's stop prompt.
|
|
120
|
+
`--no-start` also prevents startup on commands that support it. Components that
|
|
121
|
+
were already stopped stay stopped when restoring a running installation. Foreign
|
|
122
|
+
or unidentifiable processes are never stopped automatically. Foreground trials
|
|
123
|
+
resume as background processes when there is no installed service; their logs
|
|
124
|
+
are written under the selected state directory in `run/hub.log` and
|
|
125
|
+
`run/collector.log`.
|
|
126
|
+
|
|
127
|
+
Terminal output uses color for headings, status and errors. Piped output and
|
|
128
|
+
JSON remain plain; set `NO_COLOR=1` to disable color in a terminal.
|
|
83
129
|
|
|
84
130
|
## Access from another computer
|
|
85
131
|
|
|
@@ -101,16 +147,14 @@ tailscale serve --bg --tls-terminated-tcp=8081 \
|
|
|
101
147
|
If you already installed for localhost, change access without reinstalling:
|
|
102
148
|
|
|
103
149
|
```sh
|
|
104
|
-
rigscope stop
|
|
105
150
|
rigscope configure --origin https://machine.example.ts.net:8081
|
|
106
151
|
tailscale serve --bg --tls-terminated-tcp=8081 \
|
|
107
152
|
"unix:$HOME/.local/state/rigscope/run/hub.sock"
|
|
108
|
-
rigscope start
|
|
109
153
|
```
|
|
110
154
|
|
|
111
155
|
This keeps accounts, history and collector credentials. It updates the local
|
|
112
|
-
collector's destination and moves its pending samples.
|
|
113
|
-
|
|
156
|
+
collector's destination and moves its pending samples. Rigscope asks to stop
|
|
157
|
+
running components during conversion and resumes them afterward. See [Access changes](operations.md#access-changes)
|
|
114
158
|
for backup and queue checks.
|
|
115
159
|
|
|
116
160
|
### Open and check the dashboard
|
|
@@ -136,13 +180,11 @@ collectors connect through HTTPS with certificate validation.
|
|
|
136
180
|
### Return to localhost
|
|
137
181
|
|
|
138
182
|
```sh
|
|
139
|
-
rigscope stop
|
|
140
183
|
rigscope configure --local
|
|
141
184
|
tailscale serve --bg --tls-terminated-tcp=8081 off
|
|
142
|
-
rigscope start
|
|
143
185
|
```
|
|
144
186
|
|
|
145
|
-
If you
|
|
187
|
+
If you used `uninstall --keep-data`, change retained settings through the package entry
|
|
146
188
|
point, then reinstall:
|
|
147
189
|
|
|
148
190
|
```sh
|
|
@@ -151,6 +193,10 @@ npx --yes rigscope@latest configure \
|
|
|
151
193
|
npx --yes rigscope@latest install --boot
|
|
152
194
|
```
|
|
153
195
|
|
|
196
|
+
For a local port, use `configure --local --port 8086` instead. `configure` cannot
|
|
197
|
+
combine `--origin` and `--port`, because HTTPS mode uses a private Unix socket
|
|
198
|
+
instead of the port.
|
|
199
|
+
|
|
154
200
|
## Add machines and hubs
|
|
155
201
|
|
|
156
202
|
1. On the hub, choose **Add machine**, then **New machine**. Create a connection
|
|
@@ -169,7 +215,7 @@ Collectors connect outbound and need no incoming port or root access. Each can
|
|
|
169
215
|
send to up to eight hubs. Sharing is separate for each hub; network addresses
|
|
170
216
|
and full process arguments start disabled. See [Collection and sharing](monitoring.md#collection-and-sharing).
|
|
171
217
|
|
|
172
|
-
|
|
218
|
+
Changing destinations asks to stop a running collector and resumes it afterward. To replace an
|
|
173
219
|
existing machine credential, create a grant bound to that machine and use
|
|
174
220
|
`connect --replace`. For unattended enrollment, use `--token-file` with an owned
|
|
175
221
|
private file and delete it afterward; do not put the grant on the command line.
|
|
@@ -192,7 +238,9 @@ A managed runtime directory cannot be used for `try`.
|
|
|
192
238
|
|
|
193
239
|
`rigscope config` prints the private `config.json` path. The installed launcher
|
|
194
240
|
selects its own state directory. `--state-dir PATH` or `RIGSCOPE_STATE_DIR`
|
|
195
|
-
selects another installation, with separate data and service names.
|
|
241
|
+
selects another installation, with separate data and service names. The file has
|
|
242
|
+
one canonical shape: it has no version field, and its required `components` object
|
|
243
|
+
records hub and collector enablement.
|
|
196
244
|
|
|
197
245
|
Settings include component enablement, port, HTTPS origin and socket. Keep state
|
|
198
246
|
directories at mode `0700` and configuration files at `0600`. Restart after edits.
|
|
@@ -216,9 +264,35 @@ It gets `rigscope@latest` from npm, backs up the hub database and replaces the
|
|
|
216
264
|
managed runtime. Accounts, history and collector settings are retained. Only
|
|
217
265
|
components that were running are restarted; startup settings stay the same.
|
|
218
266
|
|
|
267
|
+
This retention applies to installations written in the canonical format. On a
|
|
268
|
+
pre-canonical installation, the unfinished format is reset once rather than
|
|
269
|
+
migrated: the latest CLI stages and validates the replacement, stops the hub and
|
|
270
|
+
collector completely, then removes the old configuration and history and
|
|
271
|
+
installs fresh. Back up the state directory first if that history must be kept.
|
|
272
|
+
There is no migration and no rollback to the old format; `install` also resets
|
|
273
|
+
detected pre-canonical state.
|
|
274
|
+
|
|
275
|
+
An older installed CLI cannot stage a package without the removed configuration
|
|
276
|
+
format metadata. From a pre-canonical installation, run the latest CLI directly:
|
|
277
|
+
|
|
278
|
+
```sh
|
|
279
|
+
npx --yes rigscope@latest upgrade
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Or remove the services and reinstall:
|
|
283
|
+
|
|
284
|
+
```sh
|
|
285
|
+
rigscope uninstall
|
|
286
|
+
npx --yes rigscope@latest install --boot
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Both paths stop the owned services and reset the pre-canonical configuration and
|
|
290
|
+
history. Future upgrades that stay in the canonical format keep accounts, history,
|
|
291
|
+
settings and collector identities.
|
|
292
|
+
|
|
219
293
|
| Alternative | Command |
|
|
220
294
|
| --- | --- |
|
|
221
|
-
| Select an exact published version | `rigscope upgrade --from rigscope@0.1.
|
|
295
|
+
| Select an exact published version | `rigscope upgrade --from rigscope@0.1.4` |
|
|
222
296
|
| Install a local archive | `rigscope upgrade --from ./rigscope-VERSION.tgz` |
|
|
223
297
|
| Return to the retained previous runtime | `rigscope rollback` |
|
|
224
298
|
|
|
@@ -233,13 +307,11 @@ Keep separate backups outside the machine.
|
|
|
233
307
|
### No password was printed
|
|
234
308
|
|
|
235
309
|
The `owner` password appears only when the account is created. Reinstalling with
|
|
236
|
-
saved settings keeps the old password. If you lost it,
|
|
237
|
-
|
|
310
|
+
saved settings keeps the old password. If you lost it, reset it at a private
|
|
311
|
+
prompt; Rigscope coordinates stopping and resuming the running installation:
|
|
238
312
|
|
|
239
313
|
```sh
|
|
240
|
-
rigscope stop
|
|
241
314
|
rigscope recover-password --user owner
|
|
242
|
-
rigscope start
|
|
243
315
|
```
|
|
244
316
|
|
|
245
317
|
Recovery keeps history and collector credentials. Sign in again afterward.
|
|
@@ -257,8 +329,8 @@ npx --yes rigscope@latest status
|
|
|
257
329
|
npx --yes rigscope@latest uninstall
|
|
258
330
|
```
|
|
259
331
|
|
|
260
|
-
Choose the operation you need; `uninstall`
|
|
261
|
-
|
|
332
|
+
Choose the operation you need; `uninstall` deletes this installation and its
|
|
333
|
+
data. Use `uninstall --keep-data` to preserve saved data. Use `ls -l ~/.local/bin/rigscope` to check for a link to an older
|
|
262
334
|
checkout. Back up a confirmed old launcher before removing it, then repeat
|
|
263
335
|
`install` to create the new launcher. Older services with other names may need
|
|
264
336
|
separate cleanup; do not stop unrelated services.
|
|
@@ -268,11 +340,23 @@ separate cleanup; do not stop unrelated services.
|
|
|
268
340
|
Check `rigscope logs hub` and `rigscope doctor`. If port 8081 is already in use,
|
|
269
341
|
identify the listener before stopping anything. For a fresh install, choose an
|
|
270
342
|
unused port with `install --port 8086 --boot`, or use HTTPS mode with a private
|
|
271
|
-
socket.
|
|
272
|
-
|
|
343
|
+
socket. To change a retained installation's local port, run
|
|
344
|
+
`rigscope configure --port 8086` and approve the stop prompt. Previously running
|
|
345
|
+
components resume after the change. `--origin` and `--port` cannot be combined.
|
|
273
346
|
|
|
274
347
|
## Hardware
|
|
275
348
|
|
|
349
|
+
GPU names use NVIDIA's reported model or the system's PCI name database when
|
|
350
|
+
available. Otherwise a vendor label is shown, with the PCI address separately.
|
|
351
|
+
A detected adapter can remain visible without telemetry: driver support and
|
|
352
|
+
permissions determine which counters can be read. Intel integrated adapters do
|
|
353
|
+
not necessarily expose utilization or dedicated VRAM through sysfs; shared
|
|
354
|
+
system RAM is not reported as dedicated VRAM.
|
|
355
|
+
|
|
356
|
+
History only adds historical GPU cards when stored series contain readings.
|
|
357
|
+
Empty PCI placeholder series do not create an extra card while NVIDIA's UUID
|
|
358
|
+
and model become available. Historical cards with readings remain accessible.
|
|
359
|
+
|
|
276
360
|
Collection supports Linux. CPU, memory and process readings come from procfs.
|
|
277
361
|
ARM and RISC-V CPU names are recognized; utilization uses per-core counters.
|
|
278
362
|
|
package/docs/operations.md
CHANGED
|
@@ -37,6 +37,10 @@ structured output.
|
|
|
37
37
|
rigscope upgrade
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
Approve the stop prompt if components are running; `--yes` approves it in
|
|
41
|
+
scripts. `--no-restart` leaves the upgraded installation stopped and skips live
|
|
42
|
+
health checks. Uninstall always stays stopped.
|
|
43
|
+
|
|
40
44
|
Use `--from PACKAGE` for an exact npm version or local archive. The command
|
|
41
45
|
stages the package, stops running components, takes a consistent hub database
|
|
42
46
|
backup and activates the new runtime. It restarts only the components that were
|
|
@@ -56,6 +60,14 @@ Credentials, collector identities and pending samples are retained.
|
|
|
56
60
|
`release-state.json` records which backup belongs to each runtime. Upgrading a
|
|
57
61
|
stopped installation leaves it stopped and reports live checks as skipped.
|
|
58
62
|
|
|
63
|
+
This retention applies to installations written in the canonical format. On a
|
|
64
|
+
pre-canonical installation, a one-time reset stages and validates the replacement
|
|
65
|
+
release, stops the hub and collector completely, then removes
|
|
66
|
+
the old configuration and history and installing the latest release fresh. Back
|
|
67
|
+
up the state directory first if that history must be kept. There is no migration
|
|
68
|
+
to the canonical format and no rollback to that old shape. Future upgrades that
|
|
69
|
+
stay canonical keep accounts, history, settings and collector identities.
|
|
70
|
+
|
|
59
71
|
### Roll back
|
|
60
72
|
|
|
61
73
|
```sh
|
|
@@ -66,22 +78,25 @@ Rollback uses `runtime-previous` and runs the same health checks. If that runtim
|
|
|
66
78
|
can read the current database, post-upgrade data stays intact. Otherwise it
|
|
67
79
|
restores the paired pre-upgrade backup and saves the replaced database.
|
|
68
80
|
|
|
69
|
-
A missing compatible backup stops rollback.
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
A missing compatible backup stops rollback. Installations without a recorded
|
|
82
|
+
backup can supply a compatible copy with `--backup PATH`. Never point old code at
|
|
83
|
+
a newer database schema. Rollback only applies to the previous canonical runtime;
|
|
84
|
+
a pre-canonical installation is reset by upgrade instead, with no path back to
|
|
85
|
+
that format.
|
|
72
86
|
|
|
73
87
|
## Password recovery
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
Enter a new password at the private prompt; approve stopping the running hub
|
|
90
|
+
when asked. Rigscope resumes previously running components after success:
|
|
76
91
|
|
|
77
92
|
```sh
|
|
78
|
-
rigscope stop
|
|
79
93
|
rigscope recover-password --user owner
|
|
80
|
-
rigscope start
|
|
81
94
|
```
|
|
82
95
|
|
|
83
|
-
Recovery
|
|
84
|
-
|
|
96
|
+
Recovery coordinates stopping the hub and refuses foreign or uncertain database
|
|
97
|
+
locks. Use `--yes` to approve stopping without a prompt and `--no-restart` to
|
|
98
|
+
leave it stopped. For unattended recovery, also use `--password-file` with an
|
|
99
|
+
owned `0600` file.
|
|
85
100
|
It updates the existing user's stored hash. `--enable` also clears that user's
|
|
86
101
|
disabled flag; recovery never creates a user or grants administrator access.
|
|
87
102
|
|
|
@@ -93,11 +108,16 @@ managed account.
|
|
|
93
108
|
## Access changes
|
|
94
109
|
|
|
95
110
|
Follow the commands in [Remote access](installation.md#access-from-another-computer).
|
|
96
|
-
`configure`
|
|
97
|
-
destination,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
111
|
+
`configure` asks to stop a running hub and, when changing its local collector's
|
|
112
|
+
destination, its collector. Previously running components resume after success;
|
|
113
|
+
`--yes` approves the stop prompt and `--no-restart` leaves them stopped. `--origin` changes HTTPS access, `--local`
|
|
114
|
+
returns to loopback, and `--port PORT` changes the local hub port (combine it
|
|
115
|
+
with `--local` when leaving HTTPS). `--origin` and `--port` cannot be combined
|
|
116
|
+
because HTTPS mode uses a private Unix socket instead of the port; `--local
|
|
117
|
+
--port` is allowed.
|
|
118
|
+
|
|
119
|
+
It validates the HTTPS origin, private socket or port, backs up the old settings,
|
|
120
|
+
and updates the matching local collector destination. It moves that destination's
|
|
101
121
|
whole queue directory, including SQLite WAL files. Credentials and other hubs
|
|
102
122
|
stay unchanged. An existing target queue stops the conversion to avoid merging
|
|
103
123
|
or discarding pending records. Accounts and the hub history database are retained.
|
|
@@ -173,13 +193,19 @@ The installer creates:
|
|
|
173
193
|
collector/collector.json collector identity/enrollment (created by collector)
|
|
174
194
|
outbox/<sha256(url)[0:16]>/ per-destination collector outboxes
|
|
175
195
|
backups/ private pre-upgrade/pre-activation database copies
|
|
176
|
-
install-state.json versions
|
|
196
|
+
install-state.json canonical versions/schema backups, no credentials
|
|
177
197
|
run/ private runtime directory for a Unix socket
|
|
178
198
|
<units-dir>/
|
|
179
199
|
rigscope-hub.service
|
|
180
200
|
rigscope-collector.service
|
|
181
201
|
```
|
|
182
202
|
|
|
203
|
+
`manifest.json` and `install-state.json` have one canonical shape with no
|
|
204
|
+
format-version field. An install state from the unfinished pre-canonical layout
|
|
205
|
+
is rejected rather than migrated or rewritten. Stop the old hub and collector,
|
|
206
|
+
then remove the old prefix and state directory (or reinstall) and stage the latest
|
|
207
|
+
release. There is no rollback to that old layout.
|
|
208
|
+
|
|
183
209
|
Staging does not switch `current` or start anything. After production
|
|
184
210
|
dependencies are installed and the old hub is stopped, activate explicitly:
|
|
185
211
|
|
|
@@ -443,14 +469,10 @@ detail remains request-scoped and is never persisted or included in the backup
|
|
|
443
469
|
set. Separate machines and hubs are upgraded independently. System installations
|
|
444
470
|
use the component controls in [System installation](system-installation.md#system-component-lifecycle).
|
|
445
471
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
missing record identities in a transaction before removing the old directory.
|
|
451
|
-
Stored metrics and gaps with the previous `protocolVersion: 2` envelope are
|
|
452
|
-
decoded into the current wire format at the outbox boundary; record identities
|
|
453
|
-
and previously offered gap payloads are preserved. Wire parsers remain strict.
|
|
472
|
+
The collector uses only `/api/collector/connect` and the canonical record shape.
|
|
473
|
+
There is no old-endpoint normalization, outbox migration or old-peer payload
|
|
474
|
+
conversion. Reset unfinished installations and re-enroll their collectors;
|
|
475
|
+
canonical upgrades retain their identities, credentials and pending samples.
|
|
454
476
|
|
|
455
477
|
## Measurement
|
|
456
478
|
|
package/docs/releasing.md
CHANGED
|
@@ -5,9 +5,9 @@ The first public version, `0.1.0`, is published on
|
|
|
5
5
|
[GitHub](https://github.com/Triet1402/rigscope). The package includes MIT licensing,
|
|
6
6
|
dependency notices, the security policy and [release notes](../CHANGELOG.md).
|
|
7
7
|
|
|
8
|
-
The commands below use `0.1.
|
|
9
|
-
new version everywhere; do not attempt to republish
|
|
10
|
-
can be committed and pushed to GitHub independently. The published archive and
|
|
8
|
+
The commands below use `0.1.4` as an example. For a new release, substitute its
|
|
9
|
+
new version everywhere; do not attempt to republish an already published version.
|
|
10
|
+
Documentation edits can be committed and pushed to GitHub independently. The published archive and
|
|
11
11
|
its bundled documentation stay unchanged; ship updated package documentation
|
|
12
12
|
with the next version. Keep each release tag on the revision used to build it.
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ with the next version. Keep each release tag on the revision used to build it.
|
|
|
21
21
|
4. Run the publish dry run, check the npm account, and publish the verified archive.
|
|
22
22
|
5. Verify the registry version and install it into a disposable test installation.
|
|
23
23
|
Check sign-in, fresh telemetry and the installed command.
|
|
24
|
-
6. Tag the exact source revision as `v0.1.
|
|
24
|
+
6. Tag the exact source revision as `v0.1.4`, push the tag, and create a GitHub
|
|
25
25
|
Release with the release notes, verified archive and checksum. Announce it
|
|
26
26
|
after the registry installation works.
|
|
27
27
|
|
|
@@ -45,14 +45,14 @@ npm pack --pack-destination out/release
|
|
|
45
45
|
`npm pack` runs `prepack`, which regenerates dependency notices, builds fresh
|
|
46
46
|
runtime/UI artifacts and verifies them. If notice generation changes a tracked
|
|
47
47
|
file, include that change in the release commit before producing the final
|
|
48
|
-
archive. Reuse the archive for every check below. Replace `0.1.
|
|
48
|
+
archive. Reuse the archive for every check below. Replace `0.1.4` in these
|
|
49
49
|
commands when releasing another version.
|
|
50
50
|
|
|
51
51
|
## Verify the exact archive
|
|
52
52
|
|
|
53
53
|
```sh
|
|
54
|
-
node scripts/verify-package.cjs ./out/release/rigscope-0.1.
|
|
55
|
-
npm run verify:installed -- --archive ./out/release/rigscope-0.1.
|
|
54
|
+
node scripts/verify-package.cjs ./out/release/rigscope-0.1.4.tgz
|
|
55
|
+
npm run verify:installed -- --archive ./out/release/rigscope-0.1.4.tgz
|
|
56
56
|
npm test
|
|
57
57
|
node scripts/test-runtime.cjs
|
|
58
58
|
node scripts/test.cjs --suite development
|
|
@@ -69,9 +69,9 @@ create disposable installations with separate state, launchers, ports and unit
|
|
|
69
69
|
names, then remove their services. They do not select an existing installation.
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
|
-
RIGSCOPE_TEST_ARCHIVE="$PWD/out/release/rigscope-0.1.
|
|
73
|
-
node --import tsx --test tests/cli-install.integration.ts
|
|
74
|
-
node scripts/verify-operations.cjs ./out/release/rigscope-0.1.
|
|
72
|
+
RIGSCOPE_TEST_ARCHIVE="$PWD/out/release/rigscope-0.1.4.tgz" \
|
|
73
|
+
node --import tsx --test tests/cli-install.integration.ts tests/cli-reset.integration.ts
|
|
74
|
+
node scripts/verify-operations.cjs ./out/release/rigscope-0.1.4.tgz
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
These cover installation, pairing, independent component controls, bootstrap
|
|
@@ -93,7 +93,7 @@ Record the final checksum after verification:
|
|
|
93
93
|
|
|
94
94
|
```sh
|
|
95
95
|
cd out/release
|
|
96
|
-
sha256sum rigscope-0.1.
|
|
96
|
+
sha256sum rigscope-0.1.4.tgz > SHA256SUMS
|
|
97
97
|
sha256sum --check SHA256SUMS
|
|
98
98
|
```
|
|
99
99
|
|
|
@@ -110,7 +110,7 @@ then verify the account and preview the exact archive:
|
|
|
110
110
|
```sh
|
|
111
111
|
npm login --registry=https://registry.npmjs.org
|
|
112
112
|
npm whoami --registry=https://registry.npmjs.org
|
|
113
|
-
npm publish ./out/release/rigscope-0.1.
|
|
113
|
+
npm publish ./out/release/rigscope-0.1.4.tgz --access public --tag latest \
|
|
114
114
|
--registry=https://registry.npmjs.org --dry-run
|
|
115
115
|
```
|
|
116
116
|
|
|
@@ -120,12 +120,12 @@ to publish or complete two-factor authentication.
|
|
|
120
120
|
When releasing, this command actually publishes the verified archive publicly:
|
|
121
121
|
|
|
122
122
|
```sh
|
|
123
|
-
npm publish ./out/release/rigscope-0.1.
|
|
123
|
+
npm publish ./out/release/rigscope-0.1.4.tgz --access public --tag latest \
|
|
124
124
|
--registry=https://registry.npmjs.org
|
|
125
|
-
npm view rigscope@0.1.
|
|
125
|
+
npm view rigscope@0.1.4 version dist.integrity --registry=https://registry.npmjs.org
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Then use `npx --yes rigscope@0.1.
|
|
128
|
+
Then use `npx --yes rigscope@0.1.4 install` with a disposable `--state-dir`, an
|
|
129
129
|
unused `--port` and an isolated `XDG_BIN_HOME` for the registry installation
|
|
130
130
|
check. Uninstall that test installation afterward. Use the same isolation
|
|
131
131
|
settings for all test commands so the check does not select a real installation.
|
|
@@ -150,5 +150,9 @@ be installed in the staged release; activation never silently runs npm or servic
|
|
|
150
150
|
commands. See [operations](operations.md#low-level-manifest-archive-workflow) and
|
|
151
151
|
[system installation](system-installation.md).
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
Application package versions and database migration numbers are independent.
|
|
154
|
+
Canonical configuration, installation state and collector messages carry no
|
|
155
|
+
format-version field, and pre-canonical installations are reset
|
|
156
|
+
rather than migrated. Database migrations still order irreversible SQL changes,
|
|
157
|
+
and rollback keeps its paired database backup. Never describe the removal of the
|
|
158
|
+
unfinished configuration formats as a compatibility check or migration.
|
|
@@ -33,7 +33,7 @@ The installed `rigscope system` command and `dist/system.cjs` use the same code.
|
|
|
33
33
|
collector/state.json rigscope-collector 0600
|
|
34
34
|
collector/outbox/ durable collector outboxes
|
|
35
35
|
backups/ root:root 0700, pre-upgrade/pre-rollback SQLite copies
|
|
36
|
-
system-install.json root:root 0600,
|
|
36
|
+
system-install.json root:root 0600, canonical component state/versions/backups/adoption
|
|
37
37
|
power-access.json root:root 0600, original counter modes for reversal
|
|
38
38
|
/etc/systemd/system/rigscope-hub.service root:root 0644, hub boot unit
|
|
39
39
|
/etc/systemd/system/rigscope-collector.service root:root 0644, collector boot unit
|
|
@@ -96,7 +96,16 @@ node dist/system.cjs logs hub --follow
|
|
|
96
96
|
copies a non-root-owned Node executable into the root-owned prefix, installs
|
|
97
97
|
production dependencies when `--install-deps` is given, writes private
|
|
98
98
|
configuration and both units, creates both accounts, then switches `current`.
|
|
99
|
-
Staging happens before any service is stopped.
|
|
99
|
+
Staging happens before any service is stopped. The state file has no format
|
|
100
|
+
version; its required `components` object records hub and collector enablement.
|
|
101
|
+
|
|
102
|
+
A pre-canonical system installation is reset, not migrated. `system install` and
|
|
103
|
+
`system upgrade --apply` stage and validate the replacement release, stop both
|
|
104
|
+
units completely, then remove the old configuration and history and install
|
|
105
|
+
the canonical layout fresh. Back up `/var/lib/rigscope` first if that history
|
|
106
|
+
must be kept; there is no rollback to the old format. Later upgrades that stay
|
|
107
|
+
canonical keep accounts, history, settings, collector identities and pending
|
|
108
|
+
samples, and rollback keeps its paired database backup.
|
|
100
109
|
|
|
101
110
|
- With `--enable`, `--role local` initially enables both components.
|
|
102
111
|
- With `--enable`, `--role hub` initially enables only the hub.
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[408],{4150:(e,t,r)=>{r.d(t,{Au:()=>u,_C:()=>a,eg:()=>c});var s=r(5155),n=r(2115),i=r(6304),l=r(5078);let o=(0,n.createContext)(null);function a({children:e}){let[t,r]=(0,n.useState)(null),i=(0,n.useCallback)(e=>r(t=>t?.timeMs===e?.timeMs&&t?.source===e?.source?t:e),[]),l=(0,n.useMemo)(()=>({cursor:t,setCursor:i}),[t,i]);return(0,s.jsx)(o.Provider,{value:l,children:e})}function u({series:e,fromMs:t,toMs:r,stepMs:s,gaps:l}){let a=(0,n.useId)(),[c,d]=(0,n.useState)(null),m=(0,n.useContext)(o),f=m?m.cursor:c,p=m?m.setCursor:d,h=(0,n.useRef)(null),g=(0,n.useRef)(null),y=(0,n.useCallback)(()=>{null!==h.current&&cancelAnimationFrame(h.current),h.current=null,g.current=null},[]);(0,n.useEffect)(()=>y,[y]);let b=(0,n.useMemo)(()=>(0,i.X)(e).filter(e=>e.t<=r&&e.t+s/2>=t),[e,t,r,s]),x=f&&f.timeMs>=t-s/2&&f.timeMs<=r?f.timeMs:null,v=null!==x&&f?.source===a;(0,n.useEffect)(()=>{if(!v)return;let e=e=>{"Escape"===e.key&&(y(),p(null))};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[v,p,y]);let M=()=>{y(),f?.source===a&&p(null)};return{id:a,timeMs:x,active:v,inspect:e=>{let n=Math.max(t,Math.min(r,e)),o=(0,i.bO)(b,n,s,l);g.current={timeMs:o?.t??n,source:a},null===h.current&&(h.current=requestAnimationFrame(()=>{h.current=null,p(g.current),g.current=null}))},clear:M,onKeyDown:e=>{if(y(),"Escape"===e.key)e.preventDefault(),M();else if(["ArrowLeft","ArrowRight","Home","End"].includes(e.key)){e.preventDefault();let t=(0,i.o7)(b,x,e.key);null!==t&&p({timeMs:t,source:a})}},onFocus:()=>{y(),p({timeMs:b.at(-1)?.t??r,source:a})}}}function c({id:e,timeMs:t,fraction:r,unit:i,readings:o}){let[a]=(0,n.useState)(()=>r>.5?"left":"right");return(0,s.jsxs)("div",{id:e,role:"tooltip",className:`absolute top-2 z-10 max-h-56 w-56 max-w-[calc(100%-1rem)] overflow-y-auto rounded-md border border-border bg-card p-3 text-xs text-foreground ${"left"===a?"left-2":"right-2"}`,children:[(0,s.jsx)("p",{className:"tnum font-medium",children:(0,l.r6)(t)}),(0,s.jsx)("p",{className:"mb-2 text-muted-foreground",children:"Recorded bucket average"}),(0,s.jsx)("dl",{className:"grid grid-cols-[minmax(0,1fr)_auto] items-baseline gap-x-4 gap-y-1.5",children:o.map(({key:e,label:r,color:n,point:o})=>(0,s.jsxs)("div",{className:"contents",children:[(0,s.jsxs)("dt",{className:"flex min-w-0 items-center gap-1.5",children:[(0,s.jsx)("span",{"aria-hidden":!0,className:"h-2 w-2 shrink-0 rounded-full",style:{backgroundColor:n}}),(0,s.jsx)("span",{className:"break-words",children:r})]}),(0,s.jsxs)("dd",{className:"tnum text-right",children:[o?.avg==null?"No reading":(0,l.dd)(o.avg,i),o&&o.t!==t?(0,s.jsx)("span",{className:"block text-muted-foreground",children:(0,l.ei)(o.t)}):null]})]},e))})]})}},4567:(e,t,r)=>{r.d(t,{Cv:()=>n,H9:()=>s,Lf:()=>u,P$:()=>i,RL:()=>g,bP:()=>h,er:()=>m,oB:()=>a,ue:()=>p,yv:()=>d});let s=[{metric:"cpu.usage",label:"CPU usage",shortLabel:"CPU",unit:"percent",family:"cpu",colorSlot:0,description:"Total processor utilization"},{metric:"cpu.core",label:"Per-core CPU",shortLabel:"Per-core",unit:"percent",family:"cpu",colorSlot:0,description:"Logical-core utilization; heatmap for large selections"},{metric:"cpu.temperature",label:"CPU temperature",shortLabel:"Temperature",unit:"celsius",family:"cpu",colorSlot:3,description:"Identifiable CPU hwmon sensor temperature"},{metric:"cpu.power",label:"CPU package power",shortLabel:"Power",unit:"watts",family:"cpu",colorSlot:4,description:"Top-level RAPL package power draw"},{metric:"cpu.iowait",label:"CPU I/O wait",shortLabel:"I/O wait",unit:"percent",family:"cpu",colorSlot:2,description:"Processor time waiting on I/O"},{metric:"cpu.pressure",label:"CPU pressure",shortLabel:"Pressure",unit:"percent",family:"cpu",colorSlot:4,description:"Linux PSI CPU stall pressure (avg10)"},{metric:"memory.used",label:"Memory used",shortLabel:"Memory",unit:"bytes",family:"memory",colorSlot:1,description:"Physical memory in use"},{metric:"memory.usage",label:"Memory usage",shortLabel:"Memory %",unit:"percent",family:"memory",colorSlot:1,description:"Physical memory used as a share of total"},{metric:"memory.pressure.some",label:"Memory pressure (some)",shortLabel:"Pressure some",unit:"percent",family:"memory",colorSlot:2,description:"Linux PSI memory stall pressure, some tasks (avg10)"},{metric:"memory.pressure.full",label:"Memory pressure (full)",shortLabel:"Pressure full",unit:"percent",family:"memory",colorSlot:4,description:"Linux PSI memory stall pressure, all tasks (avg10)"},{metric:"swap.used",label:"Swap used",shortLabel:"Swap",unit:"bytes",family:"swap",colorSlot:2,description:"Swap space in use"},{metric:"gpu.utilization",label:"GPU utilization",shortLabel:"Utilization",unit:"percent",family:"gpus",colorSlot:0,description:"Per-card graphics processor utilization"},{metric:"gpu.memory.used",label:"GPU memory used",shortLabel:"VRAM",unit:"bytes",family:"gpus",colorSlot:1,description:"Per-card video memory in use"},{metric:"gpu.temperature",label:"GPU temperature",shortLabel:"Temperature",unit:"celsius",family:"gpus",colorSlot:3,description:"Per-card temperature"},{metric:"gpu.power",label:"GPU power",shortLabel:"Power",unit:"watts",family:"gpus",colorSlot:4,description:"Per-card power draw"},{metric:"fs.used",label:"Filesystem used",shortLabel:"Filesystem",unit:"bytes",family:"disks",colorSlot:1,description:"Used space per mounted filesystem"},{metric:"fs.usage",label:"Filesystem usage",shortLabel:"Filesystem %",unit:"percent",family:"disks",colorSlot:1,description:"Used capacity per mounted filesystem, derived from a positive total"},{metric:"fs.inodes.usage",label:"Inode usage",shortLabel:"Inodes %",unit:"percent",family:"disks",colorSlot:2,description:"Used inodes per filesystem where the collector can read them"},{metric:"disk.read",label:"Disk read",shortLabel:"Read",unit:"bytes_per_second",family:"disks",colorSlot:0,description:"Device read throughput"},{metric:"disk.write",label:"Disk write",shortLabel:"Write",unit:"bytes_per_second",family:"disks",colorSlot:2,description:"Device write throughput"},{metric:"disk.read.latency",label:"Disk read latency",shortLabel:"Read latency",unit:"milliseconds",family:"disks",colorSlot:0,description:"Average device read latency"},{metric:"disk.write.latency",label:"Disk write latency",shortLabel:"Write latency",unit:"milliseconds",family:"disks",colorSlot:2,description:"Average device write latency"},{metric:"disk.utilization",label:"Disk utilization",shortLabel:"Utilization",unit:"percent",family:"disks",colorSlot:3,description:"Share of time the device had I/O in flight"},{metric:"io.pressure.some",label:"I/O pressure (some)",shortLabel:"I/O some",unit:"percent",family:"disks",colorSlot:3,description:"Linux PSI I/O stall pressure, some tasks (avg10)"},{metric:"io.pressure.full",label:"I/O pressure (full)",shortLabel:"I/O full",unit:"percent",family:"disks",colorSlot:4,description:"Linux PSI I/O stall pressure, all tasks (avg10)"},{metric:"net.rx",label:"Network received",shortLabel:"Received",unit:"bytes_per_second",family:"network",colorSlot:0,description:"Interface receive rate"},{metric:"net.tx",label:"Network sent",shortLabel:"Sent",unit:"bytes_per_second",family:"network",colorSlot:2,description:"Interface transmit rate"}];function n(e,t){return e.filter(r=>{for(let[s,n,i]of[["memory","memory.used","memory.usage"],["filesystem","fs.used","fs.usage"]])if(e.includes(n)&&e.includes(i)&&(r===n||r===i))return r===("percent"===t[s]?i:n);return!0})}let i=[{id:"cpu",label:"CPU",metrics:["cpu.usage","cpu.core","cpu.iowait","cpu.pressure","cpu.temperature","cpu.power"]},{id:"memory",label:"Memory",metrics:["memory.used","memory.usage","swap.used","memory.pressure.some","memory.pressure.full"]},{id:"gpu",label:"GPU",metrics:["gpu.utilization","gpu.memory.used","gpu.temperature","gpu.power"]},{id:"disk",label:"Storage",metrics:["fs.used","fs.usage","fs.inodes.usage","disk.read","disk.write","disk.read.latency","disk.write.latency","disk.utilization","io.pressure.some","io.pressure.full"]},{id:"network",label:"Network",metrics:["net.rx","net.tx"]}],l=["var(--cpu)","var(--mem)","color-mix(in oklab, var(--swap) 75%, var(--foreground))","var(--warn)","var(--crit)","var(--accent)"],o=[void 0,"7 4","2 3","10 3 2 3","4 4","1 3"];function a(e){return s.find(t=>t.metric===e)??null}function u(e,t){let r=Math.max(0,t),s=e.colorSlot+r,n=(r+Math.floor(s/l.length))%o.length;return{color:l[s%l.length],dash:o[n]}}let c={cpu:"CPU",memory:"Memory",swap:"Swap",gpus:"GPU metrics",disks:"Disk metrics",network:"Network metrics"};function d(e,t){let r=a(t);if(null===r||void 0===e)return{available:!0,reason:null};let s=e.inventory?.capabilities?.[r.family];if(!s||"supported"===s.status)return{available:!0,reason:null};let n=s.reason?.trim();return{available:!1,reason:n?`${c[r.family]}: ${s.status} — ${n}`:`${c[r.family]} are ${s.status} on this machine.`}}function m(e){if(void 0===e)return[];let t=[],r=r=>{!(t.length>=16)&&d(e,r).available&&t.push(r)};r("cpu.usage"),r("memory.used");let s=function(e){let t=e.inventory?.memory.swapTotalBytes;if("number"==typeof t)return t;let r=e.metrics?.payload.swap;return r?.status==="ok"?r.totalBytes:null}(e);return null!==s&&s>0&&r("swap.used"),p(e,[]).length>0&&(r("gpu.utilization"),r("gpu.memory.used")),t}function f(e){let t=e.includes(":")?e.slice(e.indexOf(":")+1):e;return t.length<=18?t:`${t.slice(0,10)}…${t.slice(-4)}`}function p(e,t){let r=new Set(t.filter(e=>e.metric.startsWith("gpu.")&&""!==e.resourceId).map(e=>e.resourceId)),s=[],n=new Set;(e?.inventory?.gpus??[]).forEach(e=>{let t="supported"===e.telemetry;(t||r.has(e.id))&&(n.add(e.id),s.push({id:e.id,label:e.name.trim()||f(e.id),index:s.length,totalBytes:e.memoryTotalBytes,supported:t,hasHistory:r.has(e.id)}))});let i=e?.metrics?.payload.gpus;if(i?.status==="ok")for(let e of i.devices)n.has(e.id)||"ok"!==e.status||(n.add(e.id),s.push({id:e.id,label:f(e.id),index:s.length,totalBytes:e.memoryTotalBytes,supported:!0,hasHistory:r.has(e.id)}));for(let e of[...r].sort())n.has(e)||s.push({id:e,label:f(e),index:s.length,totalBytes:null,supported:!0,hasHistory:!0});return s}function h(e,t,r){if(""===r)return a(t)?.shortLabel??"Total";let s=a(t);if(null===s)return f(r);switch(s.family){case"gpus":{let t=e?.inventory?.gpus.find(e=>e.id===r);return t?.name.trim()||f(r)}case"disks":{if(t.startsWith("fs.")){let t=e?.inventory?.filesystems.find(e=>e.id===r);return t?.mountPoint||f(r)}let s=e?.inventory?.disks.find(e=>e.id===r);return s?.name||f(r)}case"network":{let t=e?.inventory?.network.find(e=>e.id===r);return t?.name||f(r)}case"cpu":{let e=/^core:(\d+)$/.exec(r);return e?`Core ${e[1]}`:f(r)}default:return f(r)}}function g(e){switch(e){case"percent":return"%";case"bytes":return"bytes";case"bytes_per_second":return"bytes/s";case"celsius":return"\xb0C";case"watts":return"W";case"milliseconds":return"ms";default:return e}}},5078:(e,t,r)=>{r.d(t,{Ah:()=>d,I_:()=>h,O5:()=>p,Vw:()=>M,bf:()=>v,dd:()=>c,ei:()=>m,fH:()=>g,ly:()=>n,pI:()=>s,r6:()=>f,zp:()=>i});let s=[{id:"10m",shortLabel:"10m",label:"Last 10 minutes",ms:6e5,refreshMs:1e3},{id:"1h",shortLabel:"1h",label:"Last hour",ms:36e5,refreshMs:1e3},{id:"6h",shortLabel:"6h",label:"Last 6 hours",ms:216e5,refreshMs:1e3},{id:"24h",shortLabel:"24h",label:"Last 24 hours",ms:864e5,refreshMs:1e3},{id:"7d",shortLabel:"7d",label:"Last 7 days",ms:6048e5,refreshMs:1e3}];function n(e){return s.find(t=>t.id===e)??s[0]}function i(e){return n(e).refreshMs}let l=["B","KiB","MiB","GiB","TiB","PiB"];function o(e){let t=Math.abs(e),r=0;for(;t>=1024&&r<l.length-1;)t/=1024,r+=1;return{value:e<0?-t:t,unit:l[r]}}function a(e,t){return String(Number(e.toFixed(t)))}function u(e,t=""){let{value:r,unit:s}=o(e),n=Math.abs(r)>=100?0:1;return`${a(r,n)} ${s}${t}`}function c(e,t){if(null==e||!Number.isFinite(e))return"—";switch(t){case"percent":return`${a(e,1)}%`;case"bytes":return u(e);case"bytes_per_second":return u(e,"/s");case"celsius":return`${a(e,1)}\xb0C`;case"watts":return`${a(e,1)} W`;case"milliseconds":return`${a(e,10>Math.abs(e)?2:1)} ms`;default:return a(e,2)}}function d(e,t){if(!Number.isFinite(e))return"—";switch(t){case"percent":return`${a(e,0)}%`;case"bytes":case"bytes_per_second":{let{value:r,unit:s}=o(e),n=Math.abs(r)>=10||0===r?0:1;return`${a(r,n)} ${s}${"bytes_per_second"===t?"/s":""}`}case"celsius":return`${a(e,0)}\xb0C`;case"watts":return`${a(e,0)} W`;case"milliseconds":return`${a(e,+(10>Math.abs(e)))} ms`;default:return a(e,1)}}function m(e){return new Date(e).toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}function f(e){return new Date(e).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"medium"})}function p(e,t){let r=new Date(e);return t>=1728e5?r.toLocaleDateString(void 0,{month:"short",day:"numeric"}):t>=864e5?r.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hour12:!1}):r.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",hour12:!1})}function h(e){let t=Math.max(0,e);return t>=36e5?`${a(t/36e5,1)} h`:t>=6e4?`${a(t/6e4,1)} min`:`${a(t/1e3,1)} s`}function g(e,t,r){let s=e.filter(e=>e.toMs>=t&&e.fromMs<=r);if(0===s.length)return"No recorded gaps in this range.";let n=s.filter(e=>"dropped"===e.kind).length,i=s.length-n,l=[];i>0&&l.push(`${i} missed interval${1===i?"":"s"}`),n>0&&l.push(`${n} dropped report${1===n?"":"s"}`);let o=[...new Set(s.map(e=>e.reason).filter(e=>"string"==typeof e&&e.length>0))],a=o.length>0?` (${o.slice(0,3).join("; ")})`:"";return`${l.join(" and ")}${a}.`}function y(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function b(e){return"number"==typeof e&&Number.isFinite(e)}function x(e){return null===e||b(e)}function v(e){if(!y(e)||"string"!=typeof e.machineId||0===e.machineId.length||!b(e.fromMs)||!b(e.toMs)||e.toMs<=e.fromMs||!b(e.stepMs)||e.stepMs<=0||"raw"!==e.tier&&"1m"!==e.tier&&"1h"!==e.tier||"boolean"!=typeof e.truncated||!b(e.elapsedMs)||!Array.isArray(e.series)||!Array.isArray(e.gaps))return null;let t=[];for(let r of e.series){if(!y(r)||"string"!=typeof r.metric||"string"!=typeof r.resourceId||"string"!=typeof r.unit||!Array.isArray(r.points))return null;let e=[];for(let t of r.points){if(!y(t)||!b(t.t)||!x(t.min)||!x(t.max)||!x(t.avg))return null;e.push({t:t.t,min:t.min,max:t.max,avg:t.avg})}t.push({metric:r.metric,resourceId:r.resourceId,unit:r.unit,points:e})}let r=[];for(let t of e.gaps){if(!y(t)||!b(t.fromMs)||!b(t.toMs)||"missing"!==t.kind&&"dropped"!==t.kind)return null;let e={fromMs:t.fromMs,toMs:t.toMs,kind:t.kind};"string"==typeof t.reason&&(e.reason=t.reason),b(t.droppedRecords)&&(e.droppedRecords=t.droppedRecords),r.push(e)}return{machineId:e.machineId,fromMs:e.fromMs,toMs:e.toMs,stepMs:e.stepMs,tier:e.tier,series:t,gaps:r,truncated:e.truncated,elapsedMs:e.elapsedMs}}function M(e,t,r,s,i=600,l){let{fromMs:o,toMs:a}={fromMs:s-n(r).ms,toMs:s},u=new URLSearchParams({machineId:e,metrics:t.join(","),from:String(Math.floor(o)),to:String(Math.floor(a)),maxPoints:String(i)});return void 0!==l&&u.set("coreIds",l.join(",")),`/api/history?${u.toString()}`}},6304:(e,t,r)=>{function s(e,t,r,s){if(s.some(e=>t>e.fromMs&&t<e.toMs))return null;let n=0,i=e.length;for(;n<i;){let r=n+i>>>1;e[r].t<t?n=r+1:i=r}let l=e[n-1],o=e[n],a=l&&(!o||t-l.t<=o.t-t)?l:o;return!a||Math.abs(a.t-t)>r/2||s.some(e=>e.toMs>Math.min(t,a.t)&&e.fromMs<Math.max(t,a.t))?null:a}function n(e){return[...new Set(e.flatMap(e=>e.points.map(e=>e.t)))].sort((e,t)=>e-t).map(e=>({t:e,min:null,max:null,avg:null}))}function i(e,t,r,s,n,l=0){return Math.round(s+Math.max(0,Math.min(1,((r>0?(e-t)/r:0)-l)/(1-2*l)))*(n-s))}function l(e,t,r){return 0===e.length?null:"Home"===r?e[0].t:"End"===r||null===t?e.at(-1).t:"ArrowLeft"===r?[...e].reverse().find(e=>e.t<t)?.t??e[0].t:"ArrowRight"===r?e.find(e=>e.t>t)?.t??e.at(-1).t:t}r.d(t,{X:()=>n,bO:()=>s,o7:()=>l,yk:()=>i})},7284:(e,t,r)=>{r.d(t,{t:()=>c});var s=r(5155),n=r(2115),i=r(7726),l=r(5078),o=r(4567),a=r(6304),u=r(4150);function c(e){let{title:t,unit:r,series:c,fromMs:d,toMs:m,stepMs:f,gaps:p,hiddenKeys:h,onToggleSeries:g,emptyMessage:y,note:b}=e,x=(0,n.useMemo)(()=>c.filter(e=>!h.has(e.key)),[c,h]),v=(0,u.Au)({series:x,fromMs:d,toMs:m,stepMs:f,gaps:p}),M=(0,n.useRef)(null),k=(0,n.useMemo)(()=>x.flatMap(e=>e.points),[x]),w=k.some(e=>null!==e.avg||null!==e.min||null!==e.max),$=Math.max(1,m-d),j=(0,n.useMemo)(()=>(0,i.$z)(p,d,m,k),[p,d,m,k]),S=(0,n.useMemo)(()=>(0,i.kk)(r,k.flatMap(e=>[e.min,e.max,e.avg]).filter(e=>null!==e)),[r,k]),L=Math.max(1e-9,S.max-S.min),N=(0,n.useCallback)(e=>6+(Math.min(m,Math.max(d,e))-d)/$*788,[d,m,$]),P=(0,n.useCallback)(e=>6+(1-(e-S.min)/L)*148,[S.min,L]),I=(0,n.useMemo)(()=>x.map(t=>{let r=(0,i.o)(t.points,{stepMs:f,gaps:j,fromMs:d,toMs:m}).map(t=>(0,i.SG)(t,e.maxDrawPoints??601,f));return{...t,segments:r,envelope:r.filter(e=>e.length>1).map(e=>{let t=e.map(e=>`${N(e.t).toFixed(2)},${P(e.max??e.avg).toFixed(2)}`),r=[...e].reverse().map(e=>`${N(e.t).toFixed(2)},${P(e.min??e.avg).toFixed(2)}`);return`M${t.join("L")}L${r.join("L")}Z`}).join(" "),path:r.filter(e=>e.length>1).map(e=>e.map((e,t)=>`${0===t?"M":"L"}${N(e.t).toFixed(2)},${P(e.avg).toFixed(2)}`).join(" ")).join(" ")}}),[x,e.maxDrawPoints,f,j,d,m,N,P]),C=(0,n.useMemo)(()=>(function(e,t,r,s,n,o){if(0===r.length)return`${e} chart: no series selected.`;let a=r.map(e=>{let r=(0,i.T6)(e.points);return`${e.label}: ${function(e,t){let r=[];if(null!==e.latest){let s=null!==e.latestT?(0,l.ei)(e.latestT):null;r.push(`latest ${(0,l.dd)(e.latest,t)}${s?` at ${s}`:""}`)}return r.push(`average ${(0,l.dd)(e.avg,t)}`),null!==e.min&&null!==e.max&&r.push(`recorded range ${(0,l.dd)(e.min,t)} to ${(0,l.dd)(e.max,t)}`),r.join(", ")}(r,t)}`}),u=o>0?`${o} shaded interval${1===o?"":"s"} without stored data.`:"";return`${e} time-series chart. ${a.join(". ")}. ${u} Time range ${(0,l.ei)(s)} to ${(0,l.ei)(n)}.`})(t,r,x,d,m,j.length),[t,r,x,d,m,j.length]),A=(0,n.useMemo)(()=>new Map(c.map(e=>[e.key,(0,i.T6)(e.points)])),[c]),F=null===v.timeMs?[]:x.map(e=>({...e,point:(0,a.bO)(e.points,v.timeMs,f,p)})),D=null===v.timeMs?null:N(v.timeMs),R=`${v.id}-tooltip`,U=`${v.id}-instructions`,E=(0,n.useMemo)(()=>(0,s.jsxs)(s.Fragment,{children:[S.ticks.map(e=>(0,s.jsx)("line",{x1:6,x2:794,y1:P(e),y2:P(e),stroke:"var(--border)",strokeWidth:"1",vectorEffect:"non-scaling-stroke"},`grid-${e}`)),j.map(e=>(0,s.jsx)("rect",{x:N(e.fromMs),y:6,width:Math.max(1,N(e.toMs)-N(e.fromMs)),height:148,fill:"var(--muted-foreground)",opacity:"0.09"},`gap-${e.fromMs}-${e.toMs}-${e.kind}`)),I.map(e=>{let t=e.envelope;return""===t?null:(0,s.jsx)("path",{d:t,fill:e.color,opacity:"0.14",stroke:"none"},`band-${e.key}`)}),I.map(e=>{let t=e.path;return""===t?null:(0,s.jsx)("path",{d:t,fill:"none",stroke:e.color,strokeWidth:"2",strokeDasharray:e.dash,strokeLinecap:"round",strokeLinejoin:"round",vectorEffect:"non-scaling-stroke"},`line-${e.key}`)}),I.flatMap(e=>e.segments.filter(e=>1===e.length).map(t=>{let r=t[0],n=N(r.t),i=P(r.avg);return(0,s.jsx)("line",{x1:n-2.5,x2:n+2.5,y1:i,y2:i,stroke:e.color,strokeWidth:"2.5",strokeLinecap:"round",vectorEffect:"non-scaling-stroke"},`dot-${e.key}-${r.t}`)}))]}),[S,N,P,j,I]);return(0,s.jsxs)("figure",{className:`flex min-w-0 flex-col gap-2 ${e.className??""}`,children:[(0,s.jsxs)("div",{className:"flex min-h-8 flex-wrap items-center justify-between gap-2",children:[(0,s.jsx)("h3",{className:"text-xs font-medium tracking-tight text-foreground",children:t}),(0,s.jsxs)("div",{className:"flex items-center gap-3",children:[(0,s.jsx)("span",{className:"tnum shrink-0 text-xs text-muted-foreground",children:b??(0,o.RL)(r)}),e.action]})]}),w?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)("div",{className:"flex min-w-0 gap-2",children:[(0,s.jsx)("div",{"aria-hidden":!0,className:"flex h-40 w-14 shrink-0 flex-col justify-between py-0.5 text-right text-xs leading-none tnum text-muted-foreground",children:[...S.ticks].reverse().map(e=>(0,s.jsx)("span",{children:(0,l.Ah)(e,r)},e))}),(0,s.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,s.jsxs)("div",{className:"relative",onPointerLeave:v.clear,onPointerMove:e=>{let t=M.current?.getBoundingClientRect();t&&v.inspect((0,a.yk)(e.clientX,t.left,t.width,d,m,.0075))},children:[(0,s.jsx)("p",{id:U,className:"sr-only",children:"Use Left and Right arrows to inspect recorded readings, Home or End to jump, and Escape to dismiss."}),(0,s.jsxs)("svg",{ref:M,viewBox:"0 0 800 160",preserveAspectRatio:"none",role:"img","aria-label":C,tabIndex:0,"aria-describedby":`${U}${v.active?` ${R}`:""}`,onFocus:v.onFocus,onBlur:v.clear,onKeyDown:v.onKeyDown,className:"block h-40 w-full cursor-crosshair rounded-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",children:[(0,s.jsx)("title",{children:t}),E,null!==D?(0,s.jsxs)("g",{"aria-hidden":!0,pointerEvents:"none",children:[(0,s.jsx)("line",{x1:D,x2:D,y1:6,y2:154,stroke:"var(--muted-foreground)",strokeWidth:"1",strokeDasharray:"3 3",vectorEffect:"non-scaling-stroke"}),F.map(({key:e,color:t,point:r})=>r?.avg==null?null:(0,s.jsx)("circle",{cx:N(r.t),cy:P(r.avg),r:"3.5",fill:t,stroke:"var(--card)",strokeWidth:"1.5",vectorEffect:"non-scaling-stroke"},e))]}):null]}),v.active&&null!==v.timeMs&&null!==D?(0,s.jsx)(u.eg,{id:R,timeMs:v.timeMs,fraction:D/800,unit:r,readings:F}):null]}),(0,s.jsx)("div",{"aria-hidden":!0,className:"mt-1 flex justify-between gap-2 text-xs leading-tight tnum text-muted-foreground",children:(0,i.Cf)(d,m).map((e,t,r)=>(0,s.jsx)("span",{className:`${0===t?"text-left":t===r.length-1?"text-right":"hidden text-center sm:inline"}`,children:(0,l.O5)(e,$)},e))})]})]}),(0,s.jsx)("div",{className:"flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs",children:c.map(e=>{let t=!h.has(e.key),n=A.get(e.key);return(0,s.jsxs)("label",{className:"inline-flex min-h-7 cursor-pointer items-center gap-1.5",title:t?`Hide ${e.label}`:`Show ${e.label}`,children:[(0,s.jsx)("input",{type:"checkbox",checked:t,onChange:()=>g(e.key),className:"peer sr-only"}),(0,s.jsx)("span",{"aria-hidden":!0,className:"flex h-4 w-5 shrink-0 items-center justify-center rounded-sm peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:[outline-color:var(--focus)]",children:(0,s.jsx)("svg",{viewBox:"0 0 20 8",className:"h-2 w-5","aria-hidden":!0,children:(0,s.jsx)("line",{x1:"1",y1:"4",x2:"19",y2:"4",stroke:e.color,strokeWidth:"2.5",strokeDasharray:e.dash,strokeLinecap:"round"})})}),(0,s.jsx)("span",{className:t?"text-foreground":"text-muted-foreground line-through",children:e.label}),(0,s.jsx)("span",{className:"tnum text-muted-foreground",children:(0,l.dd)(n.latest,r)})]},`legend-${e.key}`)})})]}):(0,s.jsx)("div",{className:"flex min-h-32 items-center justify-center rounded-lg border border-dashed border-border px-4 py-6 text-center text-xs text-muted-foreground",children:0===c.length?y:0===x.length?"All series are hidden. Re-enable one in the legend below.":y}),!w&&c.length>0?(0,s.jsx)("div",{className:"flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs",children:c.map(e=>{let t=!h.has(e.key);return(0,s.jsxs)("label",{className:"inline-flex min-h-7 cursor-pointer items-center gap-1.5",children:[(0,s.jsx)("input",{type:"checkbox",checked:t,onChange:()=>g(e.key),className:"peer sr-only"}),(0,s.jsx)("span",{"aria-hidden":!0,className:"flex h-4 w-5 shrink-0 items-center justify-center peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:[outline-color:var(--focus)]",children:(0,s.jsx)("svg",{viewBox:"0 0 20 8",className:"h-2 w-5","aria-hidden":!0,children:(0,s.jsx)("line",{x1:"1",y1:"4",x2:"19",y2:"4",stroke:e.color,strokeWidth:"2.5",strokeDasharray:e.dash,strokeLinecap:"round"})})}),(0,s.jsx)("span",{className:t?"text-foreground":"text-muted-foreground line-through",children:e.label})]},`legend-empty-${e.key}`)})}):null]})}},7726:(e,t,r)=>{function s(e){return null!==e.avg&&Number.isFinite(e.avg)}function n(e){return null!==e&&Number.isFinite(e)?e:null}function i(e){let t=[];for(let r of e){let e=t.at(-1);if(void 0!==e&&r.fromMs<=e.toMs){e.toMs=Math.max(e.toMs,r.toMs),"missing"===e.kind&&"dropped"===r.kind&&(e.kind="dropped"),void 0===e.reason&&void 0!==r.reason&&(e.reason=r.reason),void 0===e.droppedRecords&&void 0!==r.droppedRecords&&(e.droppedRecords=r.droppedRecords);continue}t.push({...r})}return t}function l(e,t,r,n){let l=i(e.map(e=>({...e,fromMs:Math.max(t,e.fromMs),toMs:Math.min(r,e.toMs)})).filter(e=>e.toMs>e.fromMs).sort((e,t)=>e.fromMs-t.fromMs||e.toMs-t.toMs));return void 0===n?l:function(e,t,r,n){if(0===e.length)return[];let l=[...new Set(t.filter(s).map(e=>e.t).filter(e=>Number.isFinite(e)))].sort((e,t)=>e-t),o=[];for(let t of e){let e=Math.max(r,Math.min(n,t.fromMs)),s=Math.max(r,Math.min(n,t.toMs));if(s<=e)continue;let i=Math.max(r,function(e,t){let r=0,s=e.length;for(;r<s;){let n=r+s>>>1;e[n]<=t?r=n+1:s=n}return r>0?e[r-1]:null}(l,e)??e),a=Math.min(n,function(e,t){let r=0,s=e.length;for(;r<s;){let n=r+s>>>1;e[n]<t?r=n+1:s=n}return r<e.length?e[r]:null}(l,s)??s);a<=i||o.push({...t,fromMs:i,toMs:a})}return o.sort((e,t)=>e.fromMs-t.fromMs||e.toMs-t.toMs),i(o)}(l,n,t,r)}function o(e,t,r){return Math.max(e,"1h"===t?36e5:"1m"===t?6e4:100,r??0)}function a(e,t){let r=[...e].sort((e,t)=>e.t-t.t),n=l(t.gaps,t.fromMs,t.toMs),i=Math.max(1,t.stepMs),o=[],a=[],u=()=>{a.length>0&&o.push(a),a=[]};for(let e of r){if(!s(e)){u();continue}let t=a.at(-1);if(void 0!==t){let r=!e.merged&&!t.merged&&(e.t<t.t||e.t-t.t>1.5*i),s=!0===e.gapBefore||function(e,t,r){return r.some(r=>r.toMs>e&&r.fromMs<t)}(t.t,e.t,n);(r||s)&&u()}a.push(e)}return u(),o}function u(e,t,r){if(t<=0)return[];let i=[...e].sort((e,t)=>e.t-t.t);if(i.length<=t)return i.map(e=>({...e}));let l=Math.max(2,Math.ceil(i.length/t)),o=Math.max(1,r),a=[],u=[],c=!1,d=null,m=()=>{if(0===u.length)return;let e=null,t=null,r=0,s=0;for(let i of u){let l=n(i.min),o=n(i.max);null!==l&&(null===e||l<e)&&(e=l),null!==o&&(null===t||o>t)&&(t=o);let a=n(i.avg);null!==a&&(r+=a,s+=1)}a.push({t:u[0].t,min:e,max:t,avg:s>0?r/s:null,...u.length>1?{merged:!0}:{},...c?{gapBefore:!0}:{}}),u=[],c=!1};for(let e of i){if(!s(e)){m(),a.push({...e}),d=null;continue}let t=null!==d&&e.t>=d.t&&e.t-d.t<=1.5*o;u.length>0&&(!t||u.length>=l)&&m(),0===u.length&&(c=null!==d&&!t),u.push(e),d=e}return m(),a}function c(e){let t=null,r=null,s=0,i=0,l=null,o=null,a=null,u=null;for(let c of e){if(null===c.avg)continue;(null===a||c.t<a)&&(a=c.t),(null===u||c.t>u)&&(u=c.t);let e=n(c.min),d=n(c.max);null!==e&&(null===t||e<t)&&(t=e),null!==d&&(null===r||d>r)&&(r=d),null!==c.avg&&Number.isFinite(c.avg)&&(s+=c.avg,i+=1,l=c.avg,o=c.t)}return{count:i,min:t,max:r,avg:i>0?s/i:null,latest:l,latestT:o,firstT:a,lastT:u}}function d(e){if(!Number.isFinite(e)||e<=0)return 1;let t=Math.pow(10,Math.floor(Math.log10(e))),r=e/t;return(r<=1?1:r<=2?2:r<=5?5:10)*t}function m(e,t){if("percent"===e)return{min:0,max:100,ticks:[0,25,50,75,100]};let r=t.filter(e=>null!==e&&Number.isFinite(e));if(0===r.length)return{min:0,max:1,ticks:[0,1]};let s=Math.min(...r),n=Math.max(...r);if("celsius"===e){let e=Math.max(1,(n-s)*.1);s=5*Math.floor((s-e)/5),n=5*Math.ceil((n+e)/5)}else s=0,n=n>0?n:1;n<=s&&(n=s+1);let i=d((n-s)/4),l=Math.floor(s/i)*i,o=Math.ceil(n/i)*i,a=function(e,t,r=4){if(!Number.isFinite(e)||!Number.isFinite(t))return[0,1];if(t<=e)return[e];let s=d((t-e)/Math.max(1,r)),n=Math.ceil(e/s)*s,i=[];for(let e=n;e<=t+.001*s&&i.length<20;e+=s)i.push(Number(e.toPrecision(12)));return i.length>0?i:[e,t]}(l,o,4);return{min:l,max:o,ticks:a}}function f(e,t,r=4){let s=Math.max(2,Math.floor(r)),n=Math.max(0,t-e);return Array.from({length:s},(t,r)=>e+n*r/(s-1))}r.d(t,{$z:()=>l,Cf:()=>f,SG:()=>u,T6:()=>c,jl:()=>o,kk:()=>m,o:()=>a})},9429:(e,t,r)=>{r.d(t,{n:()=>l});var s=r(2115),n=r(5078);async function i(e){let t=null;try{let r=await e.json();if(null!==r&&"object"==typeof r&&"error"in r){let e=r.error;"string"==typeof e&&(t=e)}}catch{}switch(e.status){case 401:return{kind:"unauthorized",message:"Your session is no longer accepted."};case 403:return{kind:"denied",message:t??"You do not have access to this machine's history."};case 404:return{kind:"missing",message:t??"This machine is not available to the hub."};case 429:return{kind:"rate-limited",message:t??"The hub is limiting history requests."};case 503:return{kind:"unavailable",message:t??"History is temporarily unavailable."};default:return{kind:"invalid",message:t??`The hub could not answer this history query (${e.status}).`}}}function l({machineId:e,metricsKey:t,coreIdsKey:r,range:o,enabled:a=!0,autoRefresh:u=!0,refreshNonce:c=0}){let[d,m]=(0,s.useState)({machineId:e,metricsKey:t,coreIdsKey:r,range:o}),f=d.machineId===e&&d.range===o;(0,s.useEffect)(()=>{if(!f)return void m({machineId:e,metricsKey:t,coreIdsKey:r,range:o});let s=window.setTimeout(()=>m({machineId:e,metricsKey:t,coreIdsKey:r,range:o}),300);return()=>window.clearTimeout(s)},[e,t,r,o,f]);let p=f?d:{machineId:e,metricsKey:t,coreIdsKey:r,range:o},h=p.metricsKey,g=p.coreIdsKey,y=`${e}|${h}|${o}|${g??"all"}`,[b,x]=(0,s.useState)(null),[v,M]=(0,s.useState)(null),[k,w]=(0,s.useState)(null),$=(0,s.useRef)(c);return(0,s.useEffect)(()=>{let t=$.current!==c;if($.current=c,!a||!e||!h)return;let r=!0,s=!1,l=!1,d=-1/0,m=new AbortController,f=(0,n.zp)(o),p=async(t=!1)=>{if(r&&!s&&!l){s=!0,d=Date.now(),w({key:y,manual:t});try{let t=await fetch((0,n.Vw)(e,h.split(","),o,Date.now(),600,void 0===g?void 0:g.split(",").filter(Boolean)),{signal:"function"!=typeof AbortSignal.any||"function"!=typeof AbortSignal.timeout?m.signal:AbortSignal.any([m.signal,AbortSignal.timeout(2e4)]),cache:"no-store",headers:{Accept:"application/json"}});if(!t.ok)throw await i(t);let s=(0,n.bf)(await t.json());if(null===s||s.machineId!==e)throw{kind:"invalid",message:"Unexpected history response."};if(!r)return;x({key:y,range:o,result:s,loadedAt:Date.now()}),M(null)}catch(t){if(!r||m.signal.aborted)return;let e=null!==t&&"object"==typeof t&&"kind"in t&&"message"in t&&"string"==typeof t.message?t:{kind:"network",message:"Could not reach the hub. Try again."};l="rate-limited"===e.kind,["unauthorized","denied","missing"].includes(e.kind)&&x(null),M({key:y,error:e})}finally{s=!1,r&&w(null)}}},b=()=>{"visible"!==document.visibilityState||Date.now()-d<f||p()};p(t);let v=u?window.setInterval(b,f):null;return u&&document.addEventListener("visibilitychange",b),()=>{r=!1,m.abort(),null!==v&&window.clearInterval(v),document.removeEventListener("visibilitychange",b)}},[a,e,h,g,o,y,u,c]),{data:a&&b?.result.machineId===e&&b.range===o?b:null,error:a&&v?.key===y?v.error:null,loading:a&&k?.key===y,manualRefreshing:a&&k?.key===y&&k.manual}}}}]);
|