rigscope 0.1.1 → 0.1.3

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 (109) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -2
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  5. package/.next/server/app/_global-error.html +1 -1
  6. package/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/_not-found.html +1 -1
  12. package/.next/server/app/_not-found.rsc +3 -3
  13. package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  14. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
  15. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  16. package/.next/server/app/administration/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/administration.html +1 -1
  18. package/.next/server/app/administration.rsc +3 -3
  19. package/.next/server/app/administration.segments/_full.segment.rsc +3 -3
  20. package/.next/server/app/administration.segments/_tree.segment.rsc +2 -2
  21. package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +3 -3
  22. package/.next/server/app/alerts/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/alerts.html +1 -1
  24. package/.next/server/app/alerts.rsc +3 -3
  25. package/.next/server/app/alerts.segments/_full.segment.rsc +3 -3
  26. package/.next/server/app/alerts.segments/_tree.segment.rsc +2 -2
  27. package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +3 -3
  28. package/.next/server/app/connections/page_client-reference-manifest.js +1 -1
  29. package/.next/server/app/connections.html +1 -1
  30. package/.next/server/app/connections.rsc +3 -3
  31. package/.next/server/app/connections.segments/_full.segment.rsc +3 -3
  32. package/.next/server/app/connections.segments/_tree.segment.rsc +2 -2
  33. package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +3 -3
  34. package/.next/server/app/history/page.js +2 -2
  35. package/.next/server/app/history/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/history.html +1 -1
  37. package/.next/server/app/history.rsc +6 -6
  38. package/.next/server/app/history.segments/_full.segment.rsc +6 -6
  39. package/.next/server/app/history.segments/_tree.segment.rsc +2 -2
  40. package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +6 -6
  41. package/.next/server/app/index.html +1 -1
  42. package/.next/server/app/index.rsc +3 -3
  43. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  44. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  45. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  46. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  47. package/.next/server/app/login.html +1 -1
  48. package/.next/server/app/login.rsc +3 -3
  49. package/.next/server/app/login.segments/_full.segment.rsc +3 -3
  50. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  51. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -3
  52. package/.next/server/app/machines/[machineId]/page_client-reference-manifest.js +1 -1
  53. package/.next/server/app/page_client-reference-manifest.js +1 -1
  54. package/.next/server/app/processes/page.js +1 -1
  55. package/.next/server/app/processes/page_client-reference-manifest.js +1 -1
  56. package/.next/server/app/processes.html +1 -1
  57. package/.next/server/app/processes.rsc +4 -4
  58. package/.next/server/app/processes.segments/_full.segment.rsc +4 -4
  59. package/.next/server/app/processes.segments/_tree.segment.rsc +2 -2
  60. package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +4 -4
  61. package/.next/server/app-paths-manifest.json +2 -2
  62. package/.next/server/chunks/161.js +1 -1
  63. package/.next/server/chunks/168.js +1 -1
  64. package/.next/server/middleware-build-manifest.js +1 -1
  65. package/.next/server/pages/404.html +1 -1
  66. package/.next/server/pages/500.html +1 -1
  67. package/.next/server/route-cache/APP_PAGE/16d1ab46157a868f438fa01e04bf53e805c71cddec593ea1535905c59625cd42/$/login.html +1 -0
  68. package/.next/server/route-cache/APP_PAGE/16d1ab46157a868f438fa01e04bf53e805c71cddec593ea1535905c59625cd42/$/login.meta +1 -0
  69. package/.next/server/route-cache/APP_PAGE/16d1ab46157a868f438fa01e04bf53e805c71cddec593ea1535905c59625cd42/$/login.rsc +26 -0
  70. package/.next/server/route-cache/APP_PAGE/16d1ab46157a868f438fa01e04bf53e805c71cddec593ea1535905c59625cd42/$/login.segments/_full.segment.rsc +26 -0
  71. package/.next/server/route-cache/APP_PAGE/16d1ab46157a868f438fa01e04bf53e805c71cddec593ea1535905c59625cd42/$/login.segments/_tree.segment.rsc +4 -0
  72. package/.next/server/route-cache/APP_PAGE/16d1ab46157a868f438fa01e04bf53e805c71cddec593ea1535905c59625cd42/$/login.segments/login/__PAGE__.segment.rsc +32 -0
  73. package/.next/server/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.html +1 -0
  74. package/.next/server/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.meta +1 -0
  75. package/.next/server/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.rsc +24 -0
  76. package/.next/server/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.segments/_full.segment.rsc +24 -0
  77. package/.next/server/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.segments/_not-found/__PAGE__.segment.rsc +30 -0
  78. package/.next/server/route-cache/APP_PAGE/41da0ef926a63354a29f601d8e8d0a5951196c45ebcd28b7d4708fb7f56f3bf1/$/_not-found.segments/_tree.segment.rsc +4 -0
  79. package/.next/server/route-cache/APP_PAGE/c6377dd9ce6a1c2cd100eb4344e843eb4639b9ed26f84643f77680e9eb454c4b/$/index.html +1 -0
  80. package/.next/server/route-cache/APP_PAGE/c6377dd9ce6a1c2cd100eb4344e843eb4639b9ed26f84643f77680e9eb454c4b/$/index.meta +1 -0
  81. package/.next/server/route-cache/APP_PAGE/c6377dd9ce6a1c2cd100eb4344e843eb4639b9ed26f84643f77680e9eb454c4b/$/index.rsc +26 -0
  82. package/.next/server/route-cache/APP_PAGE/c6377dd9ce6a1c2cd100eb4344e843eb4639b9ed26f84643f77680e9eb454c4b/$/index.segments/__PAGE__.segment.rsc +31 -0
  83. package/.next/server/route-cache/APP_PAGE/c6377dd9ce6a1c2cd100eb4344e843eb4639b9ed26f84643f77680e9eb454c4b/$/index.segments/_full.segment.rsc +26 -0
  84. package/.next/server/route-cache/APP_PAGE/c6377dd9ce6a1c2cd100eb4344e843eb4639b9ed26f84643f77680e9eb454c4b/$/index.segments/_tree.segment.rsc +3 -0
  85. package/.next/static/chunks/408-4fe7147e38981ee1.js +1 -0
  86. package/.next/static/chunks/939-514e554087419c71.js +1 -0
  87. package/.next/static/chunks/app/history/page-69ea64476ee5db85.js +3 -0
  88. package/.next/static/chunks/app/processes/{page-e471ed23a1d5632f.js → page-0e98a4a64e829c5f.js} +1 -1
  89. package/.next/static/css/3fbf75e4c471c6a8.css +1 -0
  90. package/ARCHITECTURE.md +30 -4
  91. package/CHANGELOG.md +47 -2
  92. package/dist/cli.cjs +1627 -1042
  93. package/dist/collector.cjs +138 -226
  94. package/dist/hub.cjs +7 -20
  95. package/dist/ops.cjs +160 -33
  96. package/dist/system.cjs +869 -450
  97. package/docs/bottlenecks.md +4 -6
  98. package/docs/configuration.md +2 -0
  99. package/docs/installation.md +42 -7
  100. package/docs/operations.md +32 -16
  101. package/docs/releasing.md +21 -17
  102. package/docs/system-installation.md +11 -2
  103. package/package.json +1 -2
  104. package/.next/static/chunks/408-dc6158e0bb450ef6.js +0 -1
  105. package/.next/static/chunks/939-2600d7c8e583d5ef.js +0 -1
  106. package/.next/static/chunks/app/history/page-1475454737279ee0.js +0 -3
  107. package/.next/static/css/e45c0c7ef5ba0336.css +0 -1
  108. /package/.next/static/{NE6PGEiJxUnKRceuzUWPc → xjSDCOO8Gpm5iPO9tyRG5}/_buildManifest.js +0 -0
  109. /package/.next/static/{NE6PGEiJxUnKRceuzUWPc → xjSDCOO8Gpm5iPO9tyRG5}/_ssgManifest.js +0 -0
@@ -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 negotiated independently for each hub. Upgraded collectors
42
- advertise wire revision `0.3.0`; upgraded hubs opt in with `bottleneck-v1` in their
43
- welcome. Older hubs receive the original metric shape, including replay. Older
44
- collectors receive the original welcome shape. Upgrade the hub and collector to
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
@@ -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
@@ -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.0` to select that exact version.
30
+ the current stable release; replace it with `@0.1.3` 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.0.tgz rigscope install --boot
56
+ npx --yes --package ./rigscope-0.1.3.tgz rigscope install --boot
57
57
  ```
58
58
 
59
59
  The same installation options apply. npm still needs registry access or cached
@@ -79,7 +79,9 @@ role is a preset. Use `rigscope enable collector` to add local collection to a
79
79
  hub-only installation.
80
80
 
81
81
  `uninstall` keeps accounts, history, identity, pending samples and backups.
82
- Reinstalling reuses that data, including the existing password.
82
+ Reinstalling reuses that data, including the existing password. This retention
83
+ applies to canonical installations. Upgrading from a pre-canonical format resets
84
+ configuration and history; back up the state directory first.
83
85
 
84
86
  ## Access from another computer
85
87
 
@@ -151,6 +153,10 @@ npx --yes rigscope@latest configure \
151
153
  npx --yes rigscope@latest install --boot
152
154
  ```
153
155
 
156
+ For a local port, use `configure --local --port 8086` instead. `configure` cannot
157
+ combine `--origin` and `--port`, because HTTPS mode uses a private Unix socket
158
+ instead of the port.
159
+
154
160
  ## Add machines and hubs
155
161
 
156
162
  1. On the hub, choose **Add machine**, then **New machine**. Create a connection
@@ -192,7 +198,9 @@ A managed runtime directory cannot be used for `try`.
192
198
 
193
199
  `rigscope config` prints the private `config.json` path. The installed launcher
194
200
  selects its own state directory. `--state-dir PATH` or `RIGSCOPE_STATE_DIR`
195
- selects another installation, with separate data and service names.
201
+ selects another installation, with separate data and service names. The file has
202
+ one canonical shape: it has no version field, and its required `components` object
203
+ records hub and collector enablement.
196
204
 
197
205
  Settings include component enablement, port, HTTPS origin and socket. Keep state
198
206
  directories at mode `0700` and configuration files at `0600`. Restart after edits.
@@ -216,9 +224,35 @@ It gets `rigscope@latest` from npm, backs up the hub database and replaces the
216
224
  managed runtime. Accounts, history and collector settings are retained. Only
217
225
  components that were running are restarted; startup settings stay the same.
218
226
 
227
+ This retention applies to installations written in the canonical format. On a
228
+ pre-canonical installation, the unfinished format is reset once rather than
229
+ migrated: the latest CLI stages and validates the replacement, stops the hub and
230
+ collector completely, then removes the old configuration and history and
231
+ installs fresh. Back up the state directory first if that history must be kept.
232
+ There is no migration and no rollback to the old format; `install` also resets
233
+ detected pre-canonical state.
234
+
235
+ An older installed CLI cannot stage a package without the removed configuration
236
+ format metadata. From a pre-canonical installation, run the latest CLI directly:
237
+
238
+ ```sh
239
+ npx --yes rigscope@latest upgrade
240
+ ```
241
+
242
+ Or remove the services and reinstall:
243
+
244
+ ```sh
245
+ rigscope uninstall
246
+ npx --yes rigscope@latest install --boot
247
+ ```
248
+
249
+ Both paths stop the owned services and reset the pre-canonical configuration and
250
+ history. Future upgrades that stay in the canonical format keep accounts, history,
251
+ settings and collector identities.
252
+
219
253
  | Alternative | Command |
220
254
  | --- | --- |
221
- | Select an exact published version | `rigscope upgrade --from rigscope@0.1.0` |
255
+ | Select an exact published version | `rigscope upgrade --from rigscope@0.1.3` |
222
256
  | Install a local archive | `rigscope upgrade --from ./rigscope-VERSION.tgz` |
223
257
  | Return to the retained previous runtime | `rigscope rollback` |
224
258
 
@@ -268,8 +302,9 @@ separate cleanup; do not stop unrelated services.
268
302
  Check `rigscope logs hub` and `rigscope doctor`. If port 8081 is already in use,
269
303
  identify the listener before stopping anything. For a fresh install, choose an
270
304
  unused port with `install --port 8086 --boot`, or use HTTPS mode with a private
271
- socket. An existing installation refuses a different `--port` during reinstall;
272
- reinstalling alone does not reset its settings.
305
+ socket. To change a retained installation's local port, stop the hub and any
306
+ collector whose destination moves, run `rigscope configure --port 8086`, then
307
+ start them again. `--origin` and `--port` cannot be combined.
273
308
 
274
309
  ## Hardware
275
310
 
@@ -56,6 +56,14 @@ Credentials, collector identities and pending samples are retained.
56
56
  `release-state.json` records which backup belongs to each runtime. Upgrading a
57
57
  stopped installation leaves it stopped and reports live checks as skipped.
58
58
 
59
+ This retention applies to installations written in the canonical format. On a
60
+ pre-canonical installation, a one-time reset stages and validates the replacement
61
+ release, stops the hub and collector completely, then removes
62
+ the old configuration and history and installing the latest release fresh. Back
63
+ up the state directory first if that history must be kept. There is no migration
64
+ to the canonical format and no rollback to that old shape. Future upgrades that
65
+ stay canonical keep accounts, history, settings and collector identities.
66
+
59
67
  ### Roll back
60
68
 
61
69
  ```sh
@@ -66,9 +74,11 @@ Rollback uses `runtime-previous` and runs the same health checks. If that runtim
66
74
  can read the current database, post-upgrade data stays intact. Otherwise it
67
75
  restores the paired pre-upgrade backup and saves the replaced database.
68
76
 
69
- A missing compatible backup stops rollback. Older installations without a
70
- recorded backup can supply a compatible copy with `--backup PATH`. Never point
71
- old code at a newer database schema.
77
+ A missing compatible backup stops rollback. Installations without a recorded
78
+ backup can supply a compatible copy with `--backup PATH`. Never point old code at
79
+ a newer database schema. Rollback only applies to the previous canonical runtime;
80
+ a pre-canonical installation is reset by upgrade instead, with no path back to
81
+ that format.
72
82
 
73
83
  ## Password recovery
74
84
 
@@ -94,10 +104,14 @@ managed account.
94
104
 
95
105
  Follow the commands in [Remote access](installation.md#access-from-another-computer).
96
106
  `configure` requires a stopped hub and, when changing its local collector's
97
- destination, a stopped collector.
98
-
99
- It validates the HTTPS origin and private socket, backs up the old settings, and
100
- updates the matching local collector destination. It moves that destination's
107
+ destination, a stopped collector. `--origin` changes HTTPS access, `--local`
108
+ returns to loopback, and `--port PORT` changes the local hub port (combine it
109
+ with `--local` when leaving HTTPS). `--origin` and `--port` cannot be combined
110
+ because HTTPS mode uses a private Unix socket instead of the port; `--local
111
+ --port` is allowed.
112
+
113
+ It validates the HTTPS origin, private socket or port, backs up the old settings,
114
+ and updates the matching local collector destination. It moves that destination's
101
115
  whole queue directory, including SQLite WAL files. Credentials and other hubs
102
116
  stay unchanged. An existing target queue stops the conversion to avoid merging
103
117
  or discarding pending records. Accounts and the hub history database are retained.
@@ -173,13 +187,19 @@ The installer creates:
173
187
  collector/collector.json collector identity/enrollment (created by collector)
174
188
  outbox/<sha256(url)[0:16]>/ per-destination collector outboxes
175
189
  backups/ private pre-upgrade/pre-activation database copies
176
- install-state.json versions, schema backups, no credentials
190
+ install-state.json canonical versions/schema backups, no credentials
177
191
  run/ private runtime directory for a Unix socket
178
192
  <units-dir>/
179
193
  rigscope-hub.service
180
194
  rigscope-collector.service
181
195
  ```
182
196
 
197
+ `manifest.json` and `install-state.json` have one canonical shape with no
198
+ format-version field. An install state from the unfinished pre-canonical layout
199
+ is rejected rather than migrated or rewritten. Stop the old hub and collector,
200
+ then remove the old prefix and state directory (or reinstall) and stage the latest
201
+ release. There is no rollback to that old layout.
202
+
183
203
  Staging does not switch `current` or start anything. After production
184
204
  dependencies are installed and the old hub is stopped, activate explicitly:
185
205
 
@@ -443,14 +463,10 @@ detail remains request-scoped and is never persisted or included in the backup
443
463
  set. Separate machines and hubs are upgraded independently. System installations
444
464
  use the component controls in [System installation](system-installation.md#system-component-lifecycle).
445
465
 
446
- On upgrade from the previous collector endpoint, saved `/api/collector/v1/connect`
447
- URLs normalize to `/api/collector/connect` without changing identity, credentials,
448
- sharing policy or pending enrollment recovery proofs. The collector recovers the
449
- old URL's outbox before connecting. If both queue directories exist, it imports
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.
466
+ The collector uses only `/api/collector/connect` and the canonical record shape.
467
+ There is no old-endpoint normalization, outbox migration or old-peer payload
468
+ conversion. Reset unfinished installations and re-enroll their collectors;
469
+ canonical upgrades retain their identities, credentials and pending samples.
454
470
 
455
471
  ## Measurement
456
472
 
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.0` as an example. For a new release, substitute its
9
- new version everywhere; do not attempt to republish `0.1.0`. Documentation edits
10
- can be committed and pushed to GitHub independently. The published archive and
8
+ The commands below use `0.1.3` 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.0`, push the tag, and create a GitHub
24
+ 6. Tag the exact source revision as `v0.1.3`, 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.0` in these
48
+ archive. Reuse the archive for every check below. Replace `0.1.3` 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.0.tgz
55
- npm run verify:installed -- --archive ./out/release/rigscope-0.1.0.tgz
54
+ node scripts/verify-package.cjs ./out/release/rigscope-0.1.3.tgz
55
+ npm run verify:installed -- --archive ./out/release/rigscope-0.1.3.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.0.tgz" \
73
- node --import tsx --test tests/cli-install.integration.ts
74
- node scripts/verify-operations.cjs ./out/release/rigscope-0.1.0.tgz
72
+ RIGSCOPE_TEST_ARCHIVE="$PWD/out/release/rigscope-0.1.3.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.3.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.0.tgz > SHA256SUMS
96
+ sha256sum rigscope-0.1.3.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.0.tgz --access public --tag latest \
113
+ npm publish ./out/release/rigscope-0.1.3.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.0.tgz --access public --tag latest \
123
+ npm publish ./out/release/rigscope-0.1.3.tgz --access public --tag latest \
124
124
  --registry=https://registry.npmjs.org
125
- npm view rigscope@0.1.0 version dist.integrity --registry=https://registry.npmjs.org
125
+ npm view rigscope@0.1.3 version dist.integrity --registry=https://registry.npmjs.org
126
126
  ```
127
127
 
128
- Then use `npx --yes rigscope@0.1.0 install` with a disposable `--state-dir`, an
128
+ Then use `npx --yes rigscope@0.1.3 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
- Configuration, database schema and wire-protocol revisions are internal
154
- compatibility checks, independent of the application package version.
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, version 2 component state/versions/backups/adoption
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,7 +1,6 @@
1
1
  {
2
2
  "name": "rigscope",
3
- "version": "0.1.1",
4
- "rigscopeConfigVersion": 2,
3
+ "version": "0.1.3",
5
4
  "private": false,
6
5
  "engines": {
7
6
  "node": ">=26.0.0"
@@ -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),i=r(2115),n=r(6304),l=r(5078);let o=(0,i.createContext)(null);function a({children:e}){let[t,r]=(0,i.useState)(null),n=(0,i.useCallback)(e=>r(t=>t?.timeMs===e?.timeMs&&t?.source===e?.source?t:e),[]),l=(0,i.useMemo)(()=>({cursor:t,setCursor:n}),[t,n]);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,i.useId)(),[c,d]=(0,i.useState)(null),m=(0,i.useContext)(o),p=m?m.cursor:c,f=m?m.setCursor:d,h=(0,i.useMemo)(()=>(0,n.X)(e).filter(e=>e.t<=r&&e.t+s/2>=t),[e,t,r,s]),g=p&&p.timeMs>=t-s/2&&p.timeMs<=r?p.timeMs:null,y=null!==g&&p?.source===a;(0,i.useEffect)(()=>{if(!y)return;let e=e=>{"Escape"===e.key&&f(null)};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[y,f]);let x=e=>{let i=Math.max(t,Math.min(r,e)),o=(0,n.bO)(h,i,s,l);f({timeMs:o?.t??i,source:a})},b=()=>{p?.source===a&&f(null)};return{id:a,timeMs:g,active:y,inspect:x,clear:b,onKeyDown:e=>{if("Escape"===e.key)e.preventDefault(),b();else if(["ArrowLeft","ArrowRight","Home","End"].includes(e.key)){e.preventDefault();let t=(0,n.o7)(h,g,e.key);null!==t&&f({timeMs:t,source:a})}},onFocus:()=>x(h.at(-1)?.t??r)}}function c({id:e,timeMs:t,fraction:r,unit:i,readings:n}){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",style:{left:`clamp(8px, calc(${100*r}% ${r>.5?"- 14rem - 12px":"+ 12px"}), max(8px, calc(100% - 14rem - 8px)))`},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:n.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:()=>i,H9:()=>s,Lf:()=>u,P$:()=>n,RL:()=>g,bP:()=>h,er:()=>m,oB:()=>a,ue:()=>f,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 i(e,t){return e.filter(r=>{for(let[s,i,n]of[["memory","memory.used","memory.usage"],["filesystem","fs.used","fs.usage"]])if(e.includes(i)&&e.includes(n)&&(r===i||r===n))return r===("percent"===t[s]?n:i);return!0})}let n=[{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,i=(r+Math.floor(s/l.length))%o.length;return{color:l[s%l.length],dash:o[i]}}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 i=s.reason?.trim();return{available:!1,reason:i?`${c[r.family]}: ${s.status} — ${i}`:`${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"),f(e,[]).length>0&&(r("gpu.utilization"),r("gpu.memory.used")),t}function p(e){let t=e.includes(":")?e.slice(e.indexOf(":")+1):e;return t.length<=18?t:`${t.slice(0,10)}…${t.slice(-4)}`}function f(e,t){let r=new Set(t.filter(e=>e.metric.startsWith("gpu.")&&""!==e.resourceId).map(e=>e.resourceId)),s=[],i=new Set;(e?.inventory?.gpus??[]).forEach(e=>{let t="supported"===e.telemetry;(t||r.has(e.id))&&(i.add(e.id),s.push({id:e.id,label:e.name.trim()||p(e.id),index:s.length,totalBytes:e.memoryTotalBytes,supported:t,hasHistory:r.has(e.id)}))});let n=e?.metrics?.payload.gpus;if(n?.status==="ok")for(let e of n.devices)i.has(e.id)||"ok"!==e.status||(i.add(e.id),s.push({id:e.id,label:p(e.id),index:s.length,totalBytes:e.memoryTotalBytes,supported:!0,hasHistory:r.has(e.id)}));for(let e of[...r].sort())i.has(e)||s.push({id:e,label:p(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 p(r);switch(s.family){case"gpus":{let t=e?.inventory?.gpus.find(e=>e.id===r);return t?.name.trim()||p(r)}case"disks":{if(t.startsWith("fs.")){let t=e?.inventory?.filesystems.find(e=>e.id===r);return t?.mountPoint||p(r)}let s=e?.inventory?.disks.find(e=>e.id===r);return s?.name||p(r)}case"network":{let t=e?.inventory?.network.find(e=>e.id===r);return t?.name||p(r)}case"cpu":{let e=/^core:(\d+)$/.exec(r);return e?`Core ${e[1]}`:p(r)}default:return p(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:()=>f,Vw:()=>k,bf:()=>v,dd:()=>c,ei:()=>m,fH:()=>g,ly:()=>i,pI:()=>s,r6:()=>p,zp:()=>n});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 i(e){return s.find(t=>t.id===e)??s[0]}function n(e){return i(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),i=Math.abs(r)>=100?0:1;return`${a(r,i)} ${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),i=Math.abs(r)>=10||0===r?0:1;return`${a(r,i)} ${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 p(e){return new Date(e).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"medium"})}function f(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 i=s.filter(e=>"dropped"===e.kind).length,n=s.length-i,l=[];n>0&&l.push(`${n} missed interval${1===n?"":"s"}`),i>0&&l.push(`${i} dropped report${1===i?"":"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 x(e){return"number"==typeof e&&Number.isFinite(e)}function b(e){return null===e||x(e)}function v(e){if(!y(e)||"string"!=typeof e.machineId||0===e.machineId.length||!x(e.fromMs)||!x(e.toMs)||e.toMs<=e.fromMs||!x(e.stepMs)||e.stepMs<=0||"raw"!==e.tier&&"1m"!==e.tier&&"1h"!==e.tier||"boolean"!=typeof e.truncated||!x(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)||!x(t.t)||!b(t.min)||!b(t.max)||!b(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)||!x(t.fromMs)||!x(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),x(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 k(e,t,r,s,n=600,l){let{fromMs:o,toMs:a}={fromMs:s-i(r).ms,toMs:s},u=new URLSearchParams({machineId:e,metrics:t.join(","),from:String(Math.floor(o)),to:String(Math.floor(a)),maxPoints:String(n)});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 i=0,n=e.length;for(;i<n;){let r=i+n>>>1;e[r].t<t?i=r+1:n=r}let l=e[i-1],o=e[i],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 i(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 n(e,t,r,s,i,l=0){return Math.round(s+Math.max(0,Math.min(1,((r>0?(e-t)/r:0)-l)/(1-2*l)))*(i-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:()=>i,bO:()=>s,o7:()=>l,yk:()=>n})},7284:(e,t,r)=>{r.d(t,{t:()=>c});var s=r(5155),i=r(2115),n=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:p,gaps:f,hiddenKeys:h,onToggleSeries:g,emptyMessage:y,note:x}=e,b=(0,i.useMemo)(()=>c.filter(e=>!h.has(e.key)),[c,h]),v=(0,u.Au)({series:b,fromMs:d,toMs:m,stepMs:p,gaps:f}),k=b.flatMap(e=>e.points),M=k.some(e=>null!==e.avg||null!==e.min||null!==e.max),w=Math.max(1,m-d),$=(0,n.$z)(f,d,m),j=(0,n.kk)(r,k.flatMap(e=>[e.min,e.max,e.avg]).filter(e=>null!==e)),L=Math.max(1e-9,j.max-j.min),S=e=>6+(Math.min(m,Math.max(d,e))-d)/w*788,N=e=>6+(1-(e-j.min)/L)*148,P=(0,i.useMemo)(()=>b.map(t=>{let r=(0,n.SG)(t.points,e.maxDrawPoints??601,p),s=(0,n.o)(r,{stepMs:p,gaps:f,fromMs:d,toMs:m});return{...t,segments:s}}),[b,e.maxDrawPoints,p,f,d,m]),I=function(e,t,r,s,i,o){if(0===r.length)return`${e} chart: no series selected.`;let a=r.map(e=>{let r=(0,n.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)(i)}.`}(t,r,b,d,m,$.length),C=null===v.timeMs?[]:b.map(e=>({...e,point:(0,a.bO)(e.points,v.timeMs,p,f)})),A=null===v.timeMs?null:S(v.timeMs),D=`${v.id}-tooltip`,F=`${v.id}-instructions`;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:x??(0,o.RL)(r)}),e.action]})]}),M?(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:[...j.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,children:[(0,s.jsx)("p",{id:F,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",{viewBox:"0 0 800 160",preserveAspectRatio:"none",role:"img","aria-label":I,tabIndex:0,"aria-describedby":`${F}${v.active?` ${D}`:""}`,onPointerMove:e=>{let t=e.currentTarget.getBoundingClientRect();v.inspect((0,a.yk)(e.clientX,t.left,t.width,d,m,.0075))},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}),j.ticks.map(e=>(0,s.jsx)("line",{x1:6,x2:794,y1:N(e),y2:N(e),stroke:"var(--border)",strokeWidth:"1",vectorEffect:"non-scaling-stroke"},`grid-${e}`)),$.map(e=>(0,s.jsx)("rect",{x:S(e.fromMs),y:6,width:Math.max(1,S(e.toMs)-S(e.fromMs)),height:148,fill:"var(--muted-foreground)",opacity:"0.09"},`gap-${e.fromMs}-${e.toMs}-${e.kind}`)),P.map(e=>{var t;let r=(t=e.segments,t.filter(e=>e.length>1).map(e=>{let t=e.map(e=>`${S(e.t).toFixed(2)},${N(e.max??e.avg).toFixed(2)}`),r=[...e].reverse().map(e=>`${S(e.t).toFixed(2)},${N(e.min??e.avg).toFixed(2)}`);return`M${t.join("L")}L${r.join("L")}Z`}).join(" "));return""===r?null:(0,s.jsx)("path",{d:r,fill:e.color,opacity:"0.14",stroke:"none"},`band-${e.key}`)}),P.map(e=>{var t;let r=(t=e.segments,t.filter(e=>e.length>1).map(e=>e.map((e,t)=>`${0===t?"M":"L"}${S(e.t).toFixed(2)},${N(e.avg).toFixed(2)}`).join(" ")).join(" "));return""===r?null:(0,s.jsx)("path",{d:r,fill:"none",stroke:e.color,strokeWidth:"2",strokeDasharray:e.dash,strokeLinecap:"round",strokeLinejoin:"round",vectorEffect:"non-scaling-stroke"},`line-${e.key}`)}),P.flatMap(e=>e.segments.filter(e=>1===e.length).map(t=>{let r=t[0],i=S(r.t),n=N(r.avg);return(0,s.jsx)("line",{x1:i-2.5,x2:i+2.5,y1:n,y2:n,stroke:e.color,strokeWidth:"2.5",strokeLinecap:"round",vectorEffect:"non-scaling-stroke"},`dot-${e.key}-${r.t}`)})),null!==A?(0,s.jsxs)("g",{"aria-hidden":!0,pointerEvents:"none",children:[(0,s.jsx)("line",{x1:A,x2:A,y1:6,y2:154,stroke:"var(--muted-foreground)",strokeWidth:"1",strokeDasharray:"3 3",vectorEffect:"non-scaling-stroke"}),C.map(({key:e,color:t,point:r})=>r?.avg==null?null:(0,s.jsx)("circle",{cx:S(r.t),cy:N(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!==A?(0,s.jsx)(u.eg,{id:D,timeMs:v.timeMs,fraction:A/800,unit:r,readings:C}):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,n.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,w)},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),i=(0,n.T6)(e.points);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)(i.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===b.length?"All series are hidden. Re-enable one in the legend below.":y}),!M&&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 i(e){return null!==e&&Number.isFinite(e)?e:null}function n(e,t,r){let s=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),i=[];for(let e of s){let t=i.at(-1);if(void 0!==t&&e.fromMs<=t.toMs){t.toMs=Math.max(t.toMs,e.toMs),"missing"===t.kind&&"dropped"===e.kind&&(t.kind="dropped"),void 0===t.reason&&void 0!==e.reason&&(t.reason=e.reason),void 0===t.droppedRecords&&void 0!==e.droppedRecords&&(t.droppedRecords=e.droppedRecords);continue}i.push({...e})}return i}function l(e,t,r){return Math.max(e,"1h"===t?36e5:"1m"===t?6e4:100,r??0)}function o(e,t){let r=[...e].sort((e,t)=>e.t-t.t),i=n(t.gaps,t.fromMs,t.toMs),l=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*l),s=!0===e.gapBefore||function(e,t,r){return r.some(r=>r.toMs>e&&r.fromMs<t)}(t.t,e.t,i);(r||s)&&u()}a.push(e)}return u(),o}function a(e,t,r){if(t<=0)return[];let n=[...e].sort((e,t)=>e.t-t.t);if(n.length<=t)return n.map(e=>({...e}));let l=Math.max(2,Math.ceil(n.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 n of u){let l=i(n.min),o=i(n.max);null!==l&&(null===e||l<e)&&(e=l),null!==o&&(null===t||o>t)&&(t=o);let a=i(n.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 n){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 u(e){let t=null,r=null,s=0,n=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=i(c.min),d=i(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,n+=1,l=c.avg,o=c.t)}return{count:n,min:t,max:r,avg:n>0?s/n:null,latest:l,latestT:o,firstT:a,lastT:u}}function c(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 d(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),i=Math.max(...r);if("celsius"===e){let e=Math.max(1,(i-s)*.1);s=5*Math.floor((s-e)/5),i=5*Math.ceil((i+e)/5)}else s=0,i=i>0?i:1;i<=s&&(i=s+1);let n=c((i-s)/4),l=Math.floor(s/n)*n,o=Math.ceil(i/n)*n,a=function(e,t,r=4){if(!Number.isFinite(e)||!Number.isFinite(t))return[0,1];if(t<=e)return[e];let s=c((t-e)/Math.max(1,r)),i=Math.ceil(e/s)*s,n=[];for(let e=i;e<=t+.001*s&&n.length<20;e+=s)n.push(Number(e.toPrecision(12)));return n.length>0?n:[e,t]}(l,o,4);return{min:l,max:o,ticks:a}}function m(e,t,r=4){let s=Math.max(2,Math.floor(r)),i=Math.max(0,t-e);return Array.from({length:s},(t,r)=>e+i*r/(s-1))}r.d(t,{$z:()=>n,Cf:()=>m,SG:()=>a,T6:()=>u,jl:()=>l,kk:()=>d,o:()=>o})},9429:(e,t,r)=>{r.d(t,{n:()=>l});var s=r(2115),i=r(5078);async function n(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}),p=d.machineId===e&&d.range===o;(0,s.useEffect)(()=>{if(!p)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,p]);let f=p?d:{machineId:e,metricsKey:t,coreIdsKey:r,range:o},h=f.metricsKey,g=f.coreIdsKey,y=`${e}|${h}|${o}|${g??"all"}`,[x,b]=(0,s.useState)(null),[v,k]=(0,s.useState)(null),[M,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,p=(0,i.zp)(o),f=async(t=!1)=>{if(r&&!s&&!l){s=!0,d=Date.now(),w({key:y,manual:t});try{let t=await fetch((0,i.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 n(t);let s=(0,i.bf)(await t.json());if(null===s||s.machineId!==e)throw{kind:"invalid",message:"Unexpected history response."};if(!r)return;b({key:y,range:o,result:s,loadedAt:Date.now()}),k(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)&&b(null),k({key:y,error:e})}finally{s=!1,r&&w(null)}}},x=()=>{"visible"!==document.visibilityState||Date.now()-d<p||f()};f(t);let v=u?window.setInterval(x,p):null;return u&&document.addEventListener("visibilitychange",x),()=>{r=!1,m.abort(),null!==v&&window.clearInterval(v),document.removeEventListener("visibilitychange",x)}},[a,e,h,g,o,y,u,c]),{data:a&&x?.result.machineId===e&&x.range===o?x:null,error:a&&v?.key===y?v.error:null,loading:a&&M?.key===y,manualRefreshing:a&&M?.key===y&&M.manual}}}}]);
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[939],{592:(e,t,r)=>{r.d(t,{U8:()=>n,Q_:()=>l,FZ:()=>T});let n=1024,i=Date.parse("2000-01-01T00:00:00Z"),s=Date.parse("2200-01-01T00:00:00Z"),a=["metrics","inventory","processes"],o=["cpu","memory","swap","gpus","disks","network"],u=["outbox-age","outbox-bytes","disk-budget","write-failure","rejected"];function l(e){let t=b(e,"collector message");switch(t.type){case"hello":{k(t,["type","collectorId","runId","bootId","hostname","capabilities","expectedIntervalMs","collectorVersion"],"hello");let e=$(t.capabilities,"hello.capabilities",1,a.length).map(e=>A(e,a,"hello.capabilities"));if(new Set(e).size!==e.length||!e.includes("metrics"))throw Error("invalid hello: capabilities must be unique and include metrics");return{type:"hello",collectorId:E(t.collectorId,"collectorId"),runId:E(t.runId,"runId"),bootId:B(t.bootId,"bootId",0,128),hostname:B(t.hostname,"hostname",0,255),capabilities:e,expectedIntervalMs:P(t.expectedIntervalMs,"expectedIntervalMs",100,72e5),collectorVersion:B(t.collectorVersion,"collectorVersion",1,64)}}case"samples":{k(t,["type","mode","records"],"samples");let e=A(t.mode,["live","replay"],"samples.mode"),r=$(t.records,"samples.records",1,32).map((e,t)=>d(e,`records[${t}]`)),n=new Set;for(let e of r){let t=`${e.runId}\0${e.sequence}`;if(n.has(t))throw Error("invalid samples: duplicate record in batch");n.add(t)}return{type:"samples",mode:e,records:r}}case"inventory":return k(t,["type","capturedAt","inventory"],"inventory"),{type:"inventory",capturedAt:x(t.capturedAt,"capturedAt"),inventory:c(t.inventory)};case"status":return k(t,["type","capturedAt","delivery","failures"],"status"),{type:"status",capturedAt:x(t.capturedAt,"capturedAt"),delivery:function(e){let t=b(e,"delivery");if(k(t,["pendingRecords","pendingBytes","oldestPendingCapturedAt","inFlightRecords","droppedRecords","replaying","lastAckAt"],"delivery"),"boolean"!=typeof t.replaying)throw Error("invalid delivery: replaying");let r=(e,t)=>P(e,t,0,Number.MAX_SAFE_INTEGER);return{pendingRecords:r(t.pendingRecords,"pendingRecords"),pendingBytes:r(t.pendingBytes,"pendingBytes"),oldestPendingCapturedAt:v(t.oldestPendingCapturedAt,e=>x(e,"oldestPendingCapturedAt")),inFlightRecords:r(t.inFlightRecords,"inFlightRecords"),droppedRecords:r(t.droppedRecords,"droppedRecords"),replaying:t.replaying,lastAckAt:v(t.lastAckAt,e=>x(e,"lastAckAt"))}}(t.delivery),failures:$(t.failures,"failures",0,32).map(e=>{let t=b(e,"failure");return k(t,["metric","resourceId","reason"],"failure"),{metric:B(t.metric,"metric",1,64),resourceId:null===t.resourceId?null:I(t.resourceId),reason:B(t.reason,"reason",0,256)}})};case"detail.result":return k(t,["type","subscriptionId","capturedAt","snapshot"],"detail.result"),{type:"detail.result",subscriptionId:E(t.subscriptionId,"subscriptionId"),capturedAt:x(t.capturedAt,"capturedAt"),snapshot:function(e){let t=b(e,"process snapshot");if(k(t,["totalProcesses","truncated","inaccessible","processes"],"process snapshot"),"boolean"!=typeof t.truncated)throw Error("invalid process snapshot: truncated");let r=(e,t,r)=>v(e,e=>S(e,t,0,r));return{totalProcesses:P(t.totalProcesses,"totalProcesses",0,1e7),truncated:t.truncated,inaccessible:P(t.inaccessible,"inaccessible",0,1e7),processes:$(t.processes,"processes",0,6e3).map(e=>{let t=b(e,"process");k(t,["pid","ppid","startTicks","name","user","state","cpuPercent","memoryRssBytes","gpuMemoryBytes","ioReadBytesPerSec","ioWriteBytesPerSec","threads","unit"],"process",["command"]);let i={pid:P(t.pid,"pid",0,0x80000000),ppid:P(t.ppid,"ppid",0,0x80000000),startTicks:P(t.startTicks,"startTicks",0,Number.MAX_SAFE_INTEGER),name:B(t.name,"name",0,256),user:v(t.user,e=>B(e,"user",0,64)),state:B(t.state,"state",0,16),cpuPercent:r(t.cpuPercent,"cpuPercent",100*n),memoryRssBytes:v(t.memoryRssBytes,e=>P(e,"memoryRssBytes",0,Number.MAX_SAFE_INTEGER)),gpuMemoryBytes:v(t.gpuMemoryBytes,e=>P(e,"gpuMemoryBytes",0,Number.MAX_SAFE_INTEGER)),ioReadBytesPerSec:r(t.ioReadBytesPerSec,"ioReadBytesPerSec",1e13),ioWriteBytesPerSec:r(t.ioWriteBytesPerSec,"ioWriteBytesPerSec",1e13),threads:v(t.threads,e=>P(e,"threads",0,1e7)),unit:v(t.unit,e=>B(e,"unit",1,256))};return w(t,"command")&&(i.command=B(t.command,"command",0,4096)),i})}}(t.snapshot)};case"detail.ended":return k(t,["type","subscriptionId","reason"],"detail.ended"),{type:"detail.ended",subscriptionId:E(t.subscriptionId,"subscriptionId"),reason:A(t.reason,["expired","cancelled","withheld","unsupported","busy","failed"],"detail.ended.reason")};default:throw Error(`invalid collector message: unsupported type ${M(t.type)}`)}}function d(e,t="record"){let r=b(e,t);k(r,["collectorId","runId","bootId","sequence","capturedAt","kind","payload"],t);let i={collectorId:E(r.collectorId,"collectorId"),runId:E(r.runId,"runId"),bootId:B(r.bootId,"bootId",0,128),sequence:P(r.sequence,"sequence",0,Number.MAX_SAFE_INTEGER),capturedAt:x(r.capturedAt,"capturedAt")};if("metrics"===r.kind){let e;return{...i,kind:"metrics",payload:(k(e=b(r.payload,"metrics payload"),[...o],"metrics payload"),{cpu:y(e.cpu,"cpu",e=>{k(e,["status","usagePercent","perCore"],"cpu",["temperatureC","powerWatts","iowaitPercent","pressureSomePercent"]);let t={status:"ok",usagePercent:S(e.usagePercent,"usagePercent",0,100),perCore:$(e.perCore,"perCore",0,n).map(e=>null===e?null:S(e,"perCore",0,100))},r=g(e,"temperatureC",e=>S(e,"temperatureC",-50,200));void 0!==r&&(t.temperatureC=r);let i=g(e,"powerWatts",e=>S(e,"powerWatts",0,1e4));void 0!==i&&(t.powerWatts=i);let s=g(e,"iowaitPercent",e=>S(e,"iowaitPercent",0,100));void 0!==s&&(t.iowaitPercent=s);let a=g(e,"pressureSomePercent",e=>S(e,"pressureSomePercent",0,100));return void 0!==a&&(t.pressureSomePercent=a),t}),memory:y(e.memory,"memory",m),swap:y(e.swap,"swap",p),gpus:y(e.gpus,"gpus",e=>(k(e,["status","devices"],"gpus"),{status:"ok",devices:h($(e.devices,"gpus.devices",0,16).map(e=>f(e,"gpu",(e,t)=>{k(e,["id","status","utilizationPercent","memoryUsedBytes","memoryTotalBytes","temperatureC","powerWatts"],"gpu");let r=v(e.memoryUsedBytes,e=>P(e,"memoryUsedBytes",0,Number.MAX_SAFE_INTEGER)),n=v(e.memoryTotalBytes,e=>P(e,"memoryTotalBytes",0,Number.MAX_SAFE_INTEGER));if(null!==r&&null!==n&&r>n)throw Error("invalid gpu: memoryUsedBytes exceeds total");return{id:t,status:"ok",utilizationPercent:v(e.utilizationPercent,e=>S(e,"utilizationPercent",0,100)),memoryUsedBytes:r,memoryTotalBytes:n,temperatureC:v(e.temperatureC,e=>S(e,"temperatureC",-50,200)),powerWatts:v(e.powerWatts,e=>S(e,"powerWatts",0,1e4))}})))})),disks:y(e.disks,"disks",e=>{k(e,["status","filesystems","devices"],"disks",["pressureSomePercent","pressureFullPercent"]);let t={status:"ok",filesystems:h($(e.filesystems,"filesystems",0,64).map(e=>f(e,"filesystem",(e,t)=>{k(e,["id","status","usedBytes","totalBytes"],"filesystem",["inodesUsed","inodesTotal"]);let r=p({status:"ok",usedBytes:e.usedBytes,totalBytes:e.totalBytes}),n={id:t,status:"ok",usedBytes:r.usedBytes,totalBytes:r.totalBytes},i=g(e,"inodesUsed",e=>P(e,"inodesUsed",0,Number.MAX_SAFE_INTEGER));void 0!==i&&(n.inodesUsed=i);let s=g(e,"inodesTotal",e=>P(e,"inodesTotal",0,Number.MAX_SAFE_INTEGER));if(void 0!==s&&(n.inodesTotal=s),null!=i&&null!=s&&i>s)throw Error("invalid filesystem: inodesUsed exceeds inodesTotal");return n}))),devices:h($(e.devices,"disk devices",0,64).map(e=>f(e,"disk",(e,t)=>{k(e,["id","status","readBytesPerSec","writeBytesPerSec"],"disk",["readLatencyMs","writeLatencyMs","ioUtilizationPercent"]);let r={id:t,status:"ok",readBytesPerSec:S(e.readBytesPerSec,"readBytesPerSec",0,1e13),writeBytesPerSec:S(e.writeBytesPerSec,"writeBytesPerSec",0,1e13)},n=g(e,"readLatencyMs",e=>S(e,"readLatencyMs",0,864e5));void 0!==n&&(r.readLatencyMs=n);let i=g(e,"writeLatencyMs",e=>S(e,"writeLatencyMs",0,864e5));void 0!==i&&(r.writeLatencyMs=i);let s=g(e,"ioUtilizationPercent",e=>S(e,"ioUtilizationPercent",0,100));return void 0!==s&&(r.ioUtilizationPercent=s),r})))},r=g(e,"pressureSomePercent",e=>S(e,"pressureSomePercent",0,100));void 0!==r&&(t.pressureSomePercent=r);let n=g(e,"pressureFullPercent",e=>S(e,"pressureFullPercent",0,100));return void 0!==n&&(t.pressureFullPercent=n),t}),network:y(e.network,"network",e=>(k(e,["status","interfaces"],"network"),{status:"ok",interfaces:h($(e.interfaces,"interfaces",0,64).map(e=>f(e,"interface",(e,t)=>(k(e,["id","status","rxBytesPerSec","txBytesPerSec"],"interface"),{id:t,status:"ok",rxBytesPerSec:S(e.rxBytesPerSec,"rxBytesPerSec",0,1e13),txBytesPerSec:S(e.txBytesPerSec,"txBytesPerSec",0,1e13)}))))}))})}}if("gap"===r.kind){let e=b(r.payload,`${t}.payload`);k(e,["fromCapturedAt","toCapturedAt","droppedRecords","reason"],"gap payload");let n=x(e.fromCapturedAt,"fromCapturedAt"),s=x(e.toCapturedAt,"toCapturedAt");if(Date.parse(n)>Date.parse(s))throw Error("invalid gap: fromCapturedAt after toCapturedAt");return{...i,kind:"gap",payload:{fromCapturedAt:n,toCapturedAt:s,droppedRecords:P(e.droppedRecords,"droppedRecords",1,Number.MAX_SAFE_INTEGER),reason:A(e.reason,u,"gap.reason")}}}throw Error(`invalid ${t}: unsupported kind ${M(r.kind)}`)}function c(e){let t=b(e,"inventory");k(t,["os","cpu","memory","gpus","filesystems","disks","network","capabilities"],"inventory");let r=b(t.os,"inventory.os");k(r,["platform","release","distro","arch"],"inventory.os");let i=b(t.cpu,"inventory.cpu");k(i,["model","logicalCores"],"inventory.cpu");let s=b(t.memory,"inventory.memory");k(s,["totalBytes","swapTotalBytes"],"inventory.memory");let a=b(t.capabilities,"inventory.capabilities"),u=[...o,"processes"];k(a,[...u],"inventory.capabilities");let l={};for(let e of u){let t=b(a[e],`capability ${e}`);k(t,["status"],`capability ${e}`,["reason"]);let r={status:A(t.status,["supported","unsupported","withheld"],`capability ${e}`)};w(t,"reason")&&(r.reason=B(t.reason,"reason",0,256)),l[e]=r}let d=(e,t)=>v(e,e=>P(e,t,0,Number.MAX_SAFE_INTEGER));return{os:{platform:B(r.platform,"platform",0,64),release:B(r.release,"release",0,256),distro:v(r.distro,e=>B(e,"distro",0,256)),arch:B(r.arch,"arch",0,64)},cpu:{model:v(i.model,e=>B(e,"model",0,256)),logicalCores:P(i.logicalCores,"logicalCores",0,n)},memory:{totalBytes:d(s.totalBytes,"totalBytes"),swapTotalBytes:d(s.swapTotalBytes,"swapTotalBytes")},gpus:h($(t.gpus,"inventory.gpus",0,16).map(e=>{let t=b(e,"gpu inventory");k(t,["id","name","vendor","pciBusId","telemetry","memoryTotalBytes"],"gpu inventory",["reason"]);let r={id:I(t.id),name:B(t.name,"name",0,256),vendor:A(t.vendor,["nvidia","amd","intel","aspeed","other"],"vendor"),pciBusId:v(t.pciBusId,e=>B(e,"pciBusId",1,64)),telemetry:A(t.telemetry,["supported","unsupported"],"telemetry"),memoryTotalBytes:d(t.memoryTotalBytes,"memoryTotalBytes")};return w(t,"reason")&&(r.reason=B(t.reason,"reason",0,256)),r})),filesystems:h($(t.filesystems,"inventory.filesystems",0,64).map(e=>{let t=b(e,"filesystem inventory");return k(t,["id","mountPoint","device","fsType","totalBytes"],"filesystem inventory"),{id:I(t.id),mountPoint:B(t.mountPoint,"mountPoint",1,256),device:B(t.device,"device",0,256),fsType:B(t.fsType,"fsType",0,64),totalBytes:d(t.totalBytes,"totalBytes")}})),disks:h($(t.disks,"inventory.disks",0,64).map(e=>{let t=b(e,"disk inventory");if(k(t,["id","name","model","rotational","sizeBytes"],"disk inventory"),null!==t.rotational&&"boolean"!=typeof t.rotational)throw Error("invalid disk inventory: rotational");return{id:I(t.id),name:B(t.name,"name",1,64),model:v(t.model,e=>B(e,"model",0,256)),rotational:t.rotational,sizeBytes:d(t.sizeBytes,"sizeBytes")}})),network:h($(t.network,"inventory.network",0,64).map(e=>{let t=b(e,"interface inventory");if(k(t,["id","name","mac","addresses","virtual","state","speedMbps"],"interface inventory"),"boolean"!=typeof t.virtual)throw Error("invalid interface inventory: virtual");return{id:I(t.id),name:B(t.name,"name",1,64),mac:v(t.mac,e=>B(e,"mac",1,64)),addresses:$(t.addresses,"addresses",0,32).map(e=>{let t=b(e,"address");k(t,["family","address","prefix"],"address");let r=A(t.family,["ipv4","ipv6"],"family");return{family:r,address:B(t.address,"address",2,64),prefix:P(t.prefix,"prefix",0,"ipv4"===r?32:128)}}),virtual:t.virtual,state:A(t.state,["up","down","unknown"],"state"),speedMbps:v(t.speedMbps,e=>P(e,"speedMbps",0,1e7))}})),capabilities:l}}function p(e){k(e,["status","usedBytes","totalBytes"],"usage");let t=P(e.totalBytes,"totalBytes",0,Number.MAX_SAFE_INTEGER),r=P(e.usedBytes,"usedBytes",0,Number.MAX_SAFE_INTEGER);if(r>t)throw Error("invalid usage: usedBytes exceeds totalBytes");return{status:"ok",usedBytes:r,totalBytes:t}}function m(e){k(e,["status","usedBytes","totalBytes"],"memory",["pressureSomePercent","pressureFullPercent"]);let t=P(e.totalBytes,"totalBytes",0,Number.MAX_SAFE_INTEGER),r=P(e.usedBytes,"usedBytes",0,Number.MAX_SAFE_INTEGER);if(r>t)throw Error("invalid memory: usedBytes exceeds totalBytes");let n={status:"ok",usedBytes:r,totalBytes:t},i=g(e,"pressureSomePercent",e=>S(e,"pressureSomePercent",0,100));void 0!==i&&(n.pressureSomePercent=i);let s=g(e,"pressureFullPercent",e=>S(e,"pressureFullPercent",0,100));return void 0!==s&&(n.pressureFullPercent=s),n}function y(e,t,r){let n=b(e,t);if("ok"===n.status)return r(n);if("unavailable"===n.status)return k(n,["status","reason"],t),{status:"unavailable",reason:B(n.reason,"reason",0,256)};throw Error(`invalid ${t}: unsupported status ${M(n.status)}`)}function f(e,t,r){let n=b(e,t),i=I(n.id);if("ok"===n.status)return r(n,i);if("unavailable"===n.status)return k(n,["id","status","reason"],t),{id:i,status:"unavailable",reason:B(n.reason,"reason",0,256)};throw Error(`invalid ${t}: unsupported status ${M(n.status)}`)}function h(e){let t=new Set;for(let r of e){if(t.has(r.id))throw Error(`invalid resource list: duplicate id ${M(r.id)}`);t.add(r.id)}return e}function v(e,t){return null===e?null:t(e)}function g(e,t,r){if(w(e,t))return v(e[t],r)}function b(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))throw Error(`invalid ${t}: expected object, got ${M(e)}`);return e}function k(e,t,r,n=[]){let i=new Set([...t,...n]);for(let t of Object.keys(e))if(!i.has(t))throw Error(`invalid ${r}: unexpected field "${t}"`);for(let n of t)if(void 0===e[n])throw Error(`invalid ${r}: missing field "${n}"`);for(let t of n)if(w(e,t)&&void 0===e[t])throw Error(`invalid ${r}: ${t} must not be undefined`)}function w(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function $(e,t,r,n){if(!Array.isArray(e))throw Error(`invalid ${t}: expected array`);if(e.length<r||e.length>n)throw Error(`invalid ${t}: length ${e.length} outside ${r}..${n}`);return e}function A(e,t,r){if("string"!=typeof e||!t.includes(e))throw Error(`invalid ${r}: unexpected value ${M(e)}`);return e}function B(e,t,r,n){if("string"!=typeof e)throw Error(`invalid ${t}: expected string, got ${M(e)}`);if(e.length<r||e.length>n)throw Error(`invalid ${t}: length ${e.length} outside ${r}..${n}`);return e}function E(e,t){return B(e,t,1,128)}function I(e){return B(e,"resource id",1,256)}function P(e,t,r,n){if("number"!=typeof e||!Number.isSafeInteger(e))throw Error(`invalid ${t}: expected safe integer, got ${M(e)}`);if(e<r||e>n)throw Error(`invalid ${t}: ${e} outside ${r}..${n}`);return e}function S(e,t,r,n){if("number"!=typeof e||!Number.isFinite(e))throw Error(`invalid ${t}: expected finite number, got ${M(e)}`);if(e<r||e>n)throw Error(`invalid ${t}: ${e} outside ${r}..${n}`);return e}function x(e,t){let r=B(e,t,1,64),n=Date.parse(r);if(!Number.isFinite(n)||n<i||n>s)throw Error(`invalid ${t}: not a parseable timestamp`);return r}function M(e){try{let t=JSON.stringify(e);if("string"==typeof t)return t.length<=80?t:`${t.slice(0,77)}...`}catch{}return String(e)}function T(e){let t=C(e,"hub snapshot");_(t,["hubRunId","machines"],"hub snapshot");let r=j(t.hubRunId,"hubRunId","hub snapshot");if(!Array.isArray(t.machines))throw Error("invalid snapshot machines");let n=new Set;return{hubRunId:r,machines:t.machines.map(e=>{let t=C(e,"machine");_(t,["machineId","collectorId","hostname","connected","lastReceivedAt"],"machine",["expectedIntervalMs","metrics","inventory","delivery","displayName","tags"]);let r=j(t.machineId,"machineId","machine");if(n.has(r))throw Error("duplicate snapshot machine");n.add(r);let i=j(t.collectorId,"collectorId","machine"),s=z(t.hostname,"hostname","machine",0,N);if("boolean"!=typeof t.connected)throw Error("invalid machine connection state");let a=null===t.lastReceivedAt?null:D(t.lastReceivedAt,"lastReceivedAt","machine"),o={},u=L(t,"expectedIntervalMs")?function(e,t,r){if(null===e)return null;if(void 0===e)throw Error(`invalid ${r}: ${t} must not be undefined`);var n=e,i=t,s=r;if("number"!=typeof n||!Number.isSafeInteger(n))throw Error(`invalid ${s}: ${i} must be a safe integer, got ${G(n)}`);if(n<100||n>72e5)throw Error(`invalid ${s}: ${i} ${n} outside ${100}..${72e5}`);return n}(t.expectedIntervalMs,"expectedIntervalMs","machine"):void 0;if(L(t,"metrics")){let{receivedAt:e,...r}=C(t.metrics,"received metrics"),n=d(r);if("metrics"!==n.kind||n.collectorId!==i)throw Error("conflicting machine metrics");if(o.metrics={...n,receivedAt:D(e,"receivedAt","metrics")},o.metrics.receivedAt!==a)throw Error("conflicting metrics receipt time")}if(L(t,"inventory")&&(o.inventory=c(t.inventory)),L(t,"delivery")){let e=l(t.delivery);if("status"!==e.type)throw Error("invalid delivery status");o.delivery=e}if(L(t,"displayName")&&(o.displayName=null===t.displayName?null:z(t.displayName,"displayName","machine",0,128)),L(t,"tags")){if(!Array.isArray(t.tags)||t.tags.length>32)throw Error("invalid machine tags");o.tags=t.tags.map(e=>z(e,"tag","machine",1,64))}return{machineId:r,collectorId:i,hostname:s,connected:t.connected,lastReceivedAt:a,...void 0===u?{}:{expectedIntervalMs:u},...o}})}}let N=255,R=Date.parse("2000-01-01T00:00:00Z"),F=Date.parse("2200-01-01T00:00:00Z");function C(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))throw Error(`invalid ${t}: expected object, got ${G(e)}`);return e}function _(e,t,r,n=[]){let i=new Set([...t,...n]);for(let t of Object.keys(e))if(!i.has(t))throw Error(`invalid ${r}: unexpected field "${t}"`);for(let n of t)if(void 0===e[n])throw Error(`invalid ${r}: missing field "${n}"`);for(let t of n)if(L(e,t)&&void 0===e[t])throw Error(`invalid ${r}: ${t} must not be undefined`)}function L(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function j(e,t,r){return z(e,t,r,1,128)}function z(e,t,r,n,i){if("string"!=typeof e)throw Error(`invalid ${r}: ${t} must be a string, got ${G(e)}`);if(e.length<n||e.length>i)throw Error(`invalid ${r}: ${t} length ${e.length} outside ${n}..${i}`);return e}function D(e,t,r){let n=z(e,t,r,1,64),i=Date.parse(n);if(!Number.isFinite(i)||i<R||i>F)throw Error(`invalid ${r}: ${t} is not a parseable timestamp`);return n}function G(e){try{let t=JSON.stringify(e);if("string"==typeof t)return t.length<=80?t:`${t.slice(0,77)}...`}catch{}return String(e)}},4334:(e,t,r)=>{r.d(t,{K:()=>o,g:()=>s});var n=r(5887),i=r(7586);function s(e,t){let r=new Map;for(let s of t.machines){let a=s.metrics;if(!a)continue;let o=`${t.hubRunId}\0${a.collectorId}\0${a.runId}\0${a.sequence}`,u=e.get(s.machineId)??[],l=u.at(-1);if(l?.sampleId===o){r.set(s.machineId,u);continue}let d=o.slice(0,o.lastIndexOf("\0")+1),c=l?.sampleId.startsWith(d)?u:[],p=a.payload.memory;r.set(s.machineId,[...c,{sampleId:o,receivedAtLocal:Date.parse(a.receivedAt),cpuPercent:"ok"===a.payload.cpu.status?a.payload.cpu.usagePercent:null,memoryPercent:"ok"===p.status&&p.totalBytes>0?100*p.usedBytes/p.totalBytes:null,gapThresholdMs:(0,i.Cj)(s.expectedIntervalMs)}].slice(-n.yY))}return r}function a(e){return"number"==typeof e.gapThresholdMs&&Number.isFinite(e.gapThresholdMs)&&e.gapThresholdMs>0?e.gapThresholdMs:n.vz}function o(e,t=600,r=140){let i;if(e.length<2)return null;let s=e[0].receivedAtLocal,u=Math.max(1e3,e.at(-1).receivedAtLocal-s),l="";for(let o of e){if(null===o.cpuPercent){i=void 0;continue}let e=4+(o.receivedAtLocal-s)/u*(t-8),d=r-4-o.cpuPercent/100*(r-8),c=i?Math.min(a(i),a(o)):n.vz,p=i&&o.receivedAtLocal>=i.receivedAtLocal&&o.receivedAtLocal-i.receivedAtLocal<c;l+=`${p?"L":"M"}${e.toFixed(2)},${d.toFixed(2)} `,i=o}return l.trim()||null}},5887:(e,t,r)=>{r.d(t,{mq:()=>i,vz:()=>n,yY:()=>s});let n=15e3,i=9e4,s=180},7586:(e,t,r)=>{r.d(t,{$:()=>s,A4:()=>d,Cj:()=>i,F2:()=>m,L_:()=>p,fv:()=>c,l9:()=>u,nV:()=>l,vj:()=>a,z3:()=>o});var n=r(5887);function i(e){return null==e||"number"!=typeof e||!Number.isFinite(e)||e<=0?n.vz:Math.max(n.vz,3*e)}function s(e){if(null==e||!Number.isFinite(e)||e<0)return"—";if(e<6e4){let t=e/1e3;return Number.isInteger(t)?`${t} s`:`${t.toFixed(1)} s`}if(e<36e5){let t=e/6e4;return Number.isInteger(t)?`${t} min`:`${t.toFixed(1)} min`}let t=e/36e5;return Number.isInteger(t)?`${t} h`:`${t.toFixed(1)} h`}function a(e,t,r=i(e.expectedIntervalMs)){return function(e,t,r=n.vz){if(null===e)return"unknown";let i=Date.parse(e);return Number.isFinite(i)?t-i>=r?"stale":"live":"unknown"}(e.lastReceivedAt,t,r)}function o(e){if(null==e||!Number.isFinite(e)||e<0)return"—";let t=["B","KiB","MiB","GiB","TiB"],r=e,n=0;for(;r>=1024&&n<t.length-1;)r/=1024,n+=1;return 0===n?`${Math.round(r)} B`:`${r.toFixed(1)} ${t[n]}`}function u(e){return null!=e&&Number.isFinite(e)?`${e.toFixed(1)}%`:"—"}function l(e){if(null===e||!Number.isFinite(e))return"—";let t=Math.round(Math.max(0,e)/1e3);if(t<60)return`${t}s ago`;let r=Math.floor(t/60);if(r<60){let e=t%60;return 0===e?`${r}m ago`:`${r}m ${e}s ago`}let n=Math.floor(r/60);if(n<24){let e=r%60;return 0===e?`${n}h ago`:`${n}h ${e}m ago`}let i=Math.floor(n/24),s=n%24;return 0===s?`${i}d ago`:`${i}d ${s}h ago`}function d(e,t){if(null===e)return null;let r=Date.parse(e);return Number.isFinite(r)?t-r:null}function c(e){switch(e){case"ok":return"Live";case"degraded":return"Degraded";case"stale":return"Stale";case"disconnected":return"Disconnected";case"unseen":return"No sample yet"}}function p(e,t=n.mq){let r=e.metrics;if(!r)return{kind:"unknown"};let i=Date.parse(r.capturedAt),s=Date.parse(r.receivedAt);if(!Number.isFinite(i)||!Number.isFinite(s))return{kind:"unknown"};let a=i-s;return a>t?{kind:"ahead",skewMs:a}:a<-t?{kind:"behind",skewMs:-a}:{kind:"none"}}function m(e,t,r=i(e.expectedIntervalMs)){return{freshness:a(e,t,r),attention:function(e,t,r=i(e.expectedIntervalMs)){var n;let s=a(e,t,r);return e.metrics&&"unknown"!==s?"stale"===s?"stale":(n=e.metrics)&&("unavailable"===n.payload.cpu.status||"unavailable"===n.payload.memory.status)?"degraded":e.connected?"ok":"disconnected":"unseen"}(e,t,r),connection:e.connected?"connected":"disconnected",skew:p(e),thresholdMs:r}}},9939:(e,t,r)=>{r.d(t,{LiveProvider:()=>g,M:()=>v});var n=r(5155),i=r(2115);async function s(e){try{let t=await e.json();if(t&&"object"==typeof t&&"error"in t){let e=t.error;if("string"==typeof e)return e}}catch{}return e.statusText||null}function a(e){if(!e||"object"!=typeof e)return null;let t=e.username,r=e.csrfToken;if("string"!=typeof t||0===t.length||"string"!=typeof r||0===r.length)return null;let n=e.admin;return void 0!==n&&"boolean"!=typeof n?null:{username:t,csrfToken:r,...!0===n?{admin:!0}:{}}}async function o(){try{let e=await fetch("/api/auth/session",{cache:"no-store",signal:AbortSignal.timeout(5e3),headers:{Accept:"application/json"}});if(e.ok){try{let t=a(await e.json());if(t)return{kind:"signed-in",user:t}}catch{}return{kind:"error",detail:"unexpected session response"}}if(401===e.status)return{kind:"signed-out"};if(503===e.status)return{kind:"auth-unavailable",detail:await s(e)};return{kind:"error",detail:`unexpected status ${e.status}`}}catch{return{kind:"unreachable"}}}async function u(e,t){try{let r=await fetch("/api/auth/login",{method:"POST",cache:"no-store",signal:AbortSignal.timeout(5e3),headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({username:e,password:t})});if(r.ok){try{let e=a(await r.json());if(e)return{kind:"signed-in",user:e}}catch{}return{kind:"error",detail:"unexpected sign-in response"}}if(401===r.status)return{kind:"invalid-credentials",detail:await s(r)};if(429===r.status)return{kind:"error",detail:"too many attempts — wait a moment and try again"};if(503===r.status)return{kind:"auth-unavailable",detail:await s(r)};return{kind:"error",detail:`unexpected status ${r.status}`}}catch{return{kind:"unreachable"}}}async function l(e){try{let t=await fetch("/api/auth/logout",{method:"POST",cache:"no-store",signal:AbortSignal.timeout(5e3),headers:{"X-CSRF-Token":e,Accept:"application/json"}});if(t.ok||401===t.status)return"ok";return t.status,{kind:"error",detail:`unexpected status ${t.status}`}}catch{return"unreachable"}}async function d(e=5e3){let t=new AbortController,r=setTimeout(()=>t.abort(),e);try{let e=await fetch("/api/live",{cache:"no-store",signal:t.signal,headers:{Accept:"text/event-stream"}});if(200===e.status)return{kind:"ok"};if(401===e.status)return{kind:"unauthorized"};if(403===e.status)return{kind:"forbidden"};return{kind:"error",detail:`unexpected status ${e.status}`}}catch{return{kind:"unreachable"}}finally{clearTimeout(r);try{t.abort()}catch{}}}var c=r(592);let p=["snapshot","update","reset"];class m{source=null;lastId=null;get lastEventId(){return this.lastId}get isOpen(){return null!==this.source&&2!==this.source.readyState}start(e,t){this.close();let r=new EventSource(e);this.source=r;let n=e=>n=>{if(this.source!==r||null===this.source)return;let i=n.lastEventId;"string"==typeof i&&i.length>0&&(this.lastId=i);try{t.onSnapshot((0,c.FZ)(JSON.parse(n.data)),e,i??"")}catch{this.close(),t.onError()}};for(let e of p)r.addEventListener(e,n(e));r.onerror=()=>{this.source===r&&(this.close(),t.onError())}}close(){this.source?.close(),this.source=null}}var y=r(4334);let f=[1e3,2e3,4e3,8e3,15e3],h=(0,i.createContext)(null);function v(){let e=(0,i.useContext)(h);if(!e)throw Error("useLive must be used inside <LiveProvider>");return e}function g({children:e}){let[t,r]=(0,i.useState)({kind:"restoring"}),[s,a]=(0,i.useState)("idle"),[c,p]=(0,i.useState)(null),[v,b]=(0,i.useState)([]),[k,w]=(0,i.useState)(null),[$,A]=(0,i.useState)(null),[B,E]=(0,i.useState)(null),[I,P]=(0,i.useState)(null),[S,x]=(0,i.useState)(new Map),M=(0,i.useRef)(!0),T=(0,i.useRef)(0),N=(0,i.useRef)(null),R=(0,i.useRef)(null),F=(0,i.useRef)(0),C=(0,i.useRef)(t),_=(0,i.useRef)(0),L=(0,i.useRef)(!1),j=(0,i.useRef)(!1),z=e=>{C.current=e,r(e)},D=()=>{null!==R.current&&(clearTimeout(R.current),R.current=null)},G=()=>{_.current+=1,T.current+=1,N.current?.close(),N.current=null,D()},X=()=>{L.current=!1,b([]),x(new Map),p(null),A(null),E(null),w(null)},O=e=>{let t=C.current;("signed-in"!==t.kind||t.user.csrfToken!==e.csrfToken)&&X(),z({kind:"signed-in",user:e})},U=()=>{if("signed-in"!==C.current.kind)return;G(),a(L.current?"reconnecting":"connecting");let e=new m;N.current=e,e.start("/api/live",{onSnapshot:(t,r,n)=>{M.current&&N.current===e&&(F.current=0,L.current=!0,p(t.hubRunId),b(t.machines),w(Date.now()),A(n||null),E(r),x(e=>(0,y.g)(e,t)),a("live"))},onError:()=>{M.current&&N.current===e&&W()}})},W=async()=>{G();let e=_.current;a("reconnecting");let t=await o();if(!M.current||e!==_.current)return;if("signed-in"===t.kind)O(t.user);else if("signed-out"===t.kind){z({kind:"signed-out"}),X(),a("expired");return}else if("auth-unavailable"===t.kind){z({kind:"auth-unavailable",detail:t.detail}),X(),a("idle");return}let r=Math.min(F.current+1,f.length+1);if(F.current=r,r>f.length){a("disconnected"),Z();return}a("reconnecting"),R.current=setTimeout(()=>{q()},f[r-1])},q=async()=>{if(!M.current||j.current)return;G();let e=_.current,t=await d();if(M.current&&e===_.current){if("forbidden"===t.kind){X(),a("no-permission");return}if("unauthorized"===t.kind){let t=await o();if(!M.current||e!==_.current)return;if("signed-in"===t.kind){O(t.user),U();return}if("signed-out"===t.kind){z({kind:"signed-out"}),X(),a("expired");return}if("auth-unavailable"===t.kind){z({kind:"auth-unavailable",detail:t.detail}),X(),a("idle");return}}U()}},Z=()=>{D(),R.current=setTimeout(()=>{V()},3e4)},V=async()=>{if(!M.current||j.current)return;G();let e=_.current,t=await o();if(M.current&&e===_.current){if("signed-in"===t.kind){O(t.user),U();return}if("signed-out"===t.kind){z({kind:"signed-out"}),X(),a("expired");return}if("auth-unavailable"===t.kind){z({kind:"auth-unavailable",detail:t.detail}),X(),a("idle");return}Z()}},J=async e=>{let t=_.current,r=await o();if(M.current&&T.current===e&&t===_.current){if("signed-in"===r.kind){O(r.user),F.current=0,U();return}if("signed-out"===r.kind){z({kind:"signed-out"}),a("idle");return}if("auth-unavailable"===r.kind){z({kind:"auth-unavailable",detail:r.detail}),a("idle");return}z({kind:"restore-failed",detail:"error"===r.kind?r.detail:null}),a("idle")}},K=async(e,t)=>{G();let r=_.current,n=await u(e,t);return M.current&&r===_.current?("signed-in"===n.kind&&M.current&&(O(n.user),P(null),F.current=0,U()),n):{kind:"error",detail:"Session request superseded. Try again."}},Y=async()=>{let e=C.current;if("signed-in"!==e.kind||j.current)return;j.current=!0,G();let t=_.current;X(),a("idle");let r=await l(e.user.csrfToken);if(j.current=!1,!M.current||t!==_.current)return;if("ok"===r){z({kind:"signed-out"}),X(),a("idle"),P("Signed out.");return}let n=await o();if(M.current&&t===_.current){if("signed-in"===n.kind){O(n.user),P("Sign out failed — try again."),U();return}if("signed-out"===n.kind){z({kind:"signed-out"}),X(),a("idle"),P(null);return}if("auth-unavailable"===n.kind){z({kind:"auth-unavailable",detail:n.detail}),a("idle");return}z({kind:"restore-failed",detail:"error"===n.kind?n.detail:null}),a("idle")}};return(0,i.useEffect)(()=>(M.current=!0,T.current+=1,J(T.current),()=>{M.current=!1,G()}),[]),(0,n.jsx)(h.Provider,{value:{session:t,phase:s,hubRunId:c,machines:v,lastReceivedLocalMs:k,lastEventId:$,lastEventKind:B,notice:I,history:S,login:K,signOut:Y,retryConnection:()=>{if(M.current&&!j.current){if("signed-in"===C.current.kind){F.current=0,q();return}T.current+=1,J(T.current)}},dismissNotice:()=>P(null)},children:e})}}}]);