rigscope 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) 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 +2 -2
  13. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  14. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  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 +2 -2
  19. package/.next/server/app/administration.segments/_full.segment.rsc +2 -2
  20. package/.next/server/app/administration.segments/_tree.segment.rsc +2 -2
  21. package/.next/server/app/administration.segments/administration/__PAGE__.segment.rsc +2 -2
  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 +2 -2
  25. package/.next/server/app/alerts.segments/_full.segment.rsc +2 -2
  26. package/.next/server/app/alerts.segments/_tree.segment.rsc +2 -2
  27. package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +2 -2
  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 +2 -2
  31. package/.next/server/app/connections.segments/_full.segment.rsc +2 -2
  32. package/.next/server/app/connections.segments/_tree.segment.rsc +2 -2
  33. package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +2 -2
  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 +5 -5
  38. package/.next/server/app/history.segments/_full.segment.rsc +5 -5
  39. package/.next/server/app/history.segments/_tree.segment.rsc +2 -2
  40. package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +5 -5
  41. package/.next/server/app/index.html +1 -1
  42. package/.next/server/app/index.rsc +2 -2
  43. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  44. package/.next/server/app/index.segments/_full.segment.rsc +2 -2
  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 +2 -2
  49. package/.next/server/app/login.segments/_full.segment.rsc +2 -2
  50. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  51. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  52. package/.next/server/app/machines/[machineId]/page.js +1 -1
  53. package/.next/server/app/machines/[machineId]/page_client-reference-manifest.js +1 -1
  54. package/.next/server/app/page_client-reference-manifest.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 +2 -2
  58. package/.next/server/app/processes.segments/_full.segment.rsc +2 -2
  59. package/.next/server/app/processes.segments/_tree.segment.rsc +2 -2
  60. package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +2 -2
  61. package/.next/server/app-paths-manifest.json +2 -2
  62. package/.next/server/chunks/168.js +1 -1
  63. package/.next/server/middleware-build-manifest.js +1 -1
  64. package/.next/server/pages/404.html +1 -1
  65. package/.next/server/pages/500.html +1 -1
  66. package/.next/static/chunks/408-4fe7147e38981ee1.js +1 -0
  67. package/.next/static/chunks/app/history/page-22be927a4c3a9c76.js +3 -0
  68. package/.next/static/chunks/app/machines/[machineId]/page-916ee73de5eb067d.js +1 -0
  69. package/.next/static/css/3fbf75e4c471c6a8.css +1 -0
  70. package/CHANGELOG.md +27 -0
  71. package/README.md +53 -136
  72. package/dist/collector.cjs +9 -1
  73. package/dist/hub.cjs +14 -5
  74. package/dist/ops.cjs +8 -4
  75. package/docs/bottlenecks.md +1 -1
  76. package/docs/configuration.md +85 -0
  77. package/docs/development.md +1 -1
  78. package/docs/installation.md +205 -376
  79. package/docs/monitoring.md +112 -0
  80. package/docs/operations.md +103 -68
  81. package/docs/releasing.md +16 -14
  82. package/docs/scale-validation.md +34 -3
  83. package/docs/stress-2026-11-04/180301-probe-m100-u1-s1-20000ms.json +412 -0
  84. package/docs/stress-2026-11-04/180335-probe-m200-u1-s1-20000ms.json +412 -0
  85. package/docs/stress-2026-11-04/180409-probe-m400-u1-s1-20000ms.json +412 -0
  86. package/docs/stress-2026-11-04/180443-probe-m800-u1-s1-20000ms.json +412 -0
  87. package/docs/stress-2026-11-04/180518-probe-m600-u1-s1-20000ms.json +412 -0
  88. package/docs/stress-2026-11-04/180553-probe-m500-u1-s1-20000ms.json +412 -0
  89. package/docs/stress-2026-11-04/180628-probe-m550-u1-s1-20000ms.json +412 -0
  90. package/docs/stress-2026-11-04/180716-probe-m800-u1-s0-20000ms.json +415 -0
  91. package/docs/stress-2026-11-04/180751-probe-m1600-u1-s0-20000ms.json +415 -0
  92. package/docs/stress-2026-11-04/180828-probe-m3200-u1-s0-20000ms.json +416 -0
  93. package/docs/stress-2026-11-04/180941-probe-m2400-u1-s0-20000ms.json +416 -0
  94. package/docs/stress-2026-11-04/181031-probe-m2000-u1-s0-20000ms.json +416 -0
  95. package/docs/stress-2026-11-04/181114-probe-m1800-u1-s0-20000ms.json +416 -0
  96. package/docs/stress-2026-11-04/181203-probe-m100-u64-s64-20000ms.json +418 -0
  97. package/docs/stress-2026-11-04/181304-probe-m200-u64-s64-20000ms.json +418 -0
  98. package/docs/stress-2026-11-04/181405-probe-m400-u64-s64-20000ms.json +418 -0
  99. package/docs/stress-2026-11-04/181507-probe-m500-u64-s64-20000ms.json +418 -0
  100. package/docs/stress-2026-11-04/181609-probe-m450-u64-s64-20000ms.json +418 -0
  101. package/docs/stress-2026-11-04/181845-probe-m2-u2-s2-3000ms.json +419 -0
  102. package/docs/stress-2026-11-04/181931-probe-m500-u64-s64-30000ms.json +420 -0
  103. package/docs/stress-2026-11-04/182108-probe-m1800-u1-s0-120000ms.json +418 -0
  104. package/docs/stress-2026-11-04/182354-probe-m1200-u1-s0-120000ms.json +418 -0
  105. package/docs/stress-2026-11-04/182625-probe-m900-u1-s0-120000ms.json +418 -0
  106. package/docs/stress-2026-11-04/182847-probe-m1050-u1-s0-120000ms.json +418 -0
  107. package/docs/stress-2026-11-04/183112-probe-m1125-u1-s0-120000ms.json +418 -0
  108. package/docs/stress-2026-11-04/193608-probe-m500-u64-s64-120000ms.json +420 -0
  109. package/docs/stress-2026-11-04/193909-probe-m529-u1-s1-15000ms.json +420 -0
  110. package/docs/stress-2026-11-04/193940-probe-m530-u1-s1-15000ms.json +420 -0
  111. package/docs/stress-2026-11-04/194011-probe-m100-u1-s65-10000ms.json +421 -0
  112. package/docs/stress-2026-11-04/README.md +205 -0
  113. package/docs/stress-2026-11-04/index.jsonl +29 -0
  114. package/docs/stress-2026-11-04/manifest.json +13 -0
  115. package/docs/stress-2026-11-04/results.html +22 -0
  116. package/docs/system-installation.md +195 -0
  117. package/package.json +9 -1
  118. package/packaging/system/README.md +1 -1
  119. package/.next/static/chunks/408-18819c6490a5f8d3.js +0 -1
  120. package/.next/static/chunks/app/history/page-3fa5846eca26b7f7.js +0 -3
  121. package/.next/static/chunks/app/machines/[machineId]/page-a5aa1d8676272f38.js +0 -1
  122. package/.next/static/css/e41ccbccc3afaae5.css +0 -1
  123. /package/.next/static/{DZKWF9ur7H5wI0c7RAhdq → npHoP6NSY976Yaye-xi86}/_buildManifest.js +0 -0
  124. /package/.next/static/{DZKWF9ur7H5wI0c7RAhdq → npHoP6NSY976Yaye-xi86}/_ssgManifest.js +0 -0
package/README.md CHANGED
@@ -1,158 +1,75 @@
1
1
  # Rigscope
2
2
 
3
- Your machines, in view. A self-hosted Linux system and process monitor for one machine or a small fleet. A collector samples each machine and connects outbound to one or more independently operated hubs. Each hub owns its users, permissions, SQLite history and alerts.
3
+ Your machines, in view. A self-hosted Linux system and process monitor.
4
4
 
5
- Requires Linux, Node.js 26+ with npm, and a working systemd user manager for background services. Install a published release with:
5
+ View CPU, memory, GPU, disk and network readings, browse History, inspect running
6
+ processes and set alerts. Run a hub for the dashboard and a collector on each
7
+ machine you want to monitor. The default installation runs both on this computer.
8
+
9
+ ## Install
10
+
11
+ Requires **Linux, Node.js 26+ with npm, and systemd** for background services.
6
12
 
7
13
  ```sh
8
14
  npx --yes rigscope@latest install --boot
9
- ~/.local/bin/rigscope
10
15
  ```
11
16
 
12
- If the npm release is not available yet, use the [release archive instructions](docs/installation.md#install-from-an-archive). No global npm installation or source checkout is required.
17
+ Save the generated `owner` password and open the printed dashboard URL
18
+ (normally `http://127.0.0.1:8081`). The services keep running after you close the
19
+ terminal. `--boot` starts them at boot; omit it to start at login instead.
20
+
21
+ Add `~/.local/bin` to PATH to use `rigscope`. You can also run
22
+ `~/.local/bin/rigscope` directly. No global npm install or source checkout is needed.
13
23
 
14
- Save the generated `owner` password and open the printed URL. The default installation starts separate hub and collector services. `--boot` enables user lingering; without it, startup is at login. The installer reports any host authorization needed. Add `~/.local/bin` to PATH to use the commands below. Bare `rigscope` shows status.
24
+ To try Rigscope in the terminal before installing services:
15
25
 
16
26
  ```sh
17
- rigscope status
18
- rigscope logs hub
19
- rigscope stop collector
20
- rigscope start collector
21
- rigscope upgrade
22
- rigscope rollback
27
+ npx --yes rigscope@latest try
23
28
  ```
24
29
 
25
- For a foreground trial before installing services, run `npx --yes rigscope@latest try`. It uses separate trial state and stops with Ctrl+C. For a collector reporting to an existing hub, install with `--role collector`, then use `rigscope connect https://your-hub.example.com` and paste an Add machine grant at the private prompt. Each collector supports up to eight hubs.
30
+ The trial uses separate data and stops with Ctrl+C.
26
31
 
27
- Rigscope includes real resource telemetry, fleet and machine views, durable History, on-demand Processes, alerts/webhooks and user/collector administration. Process inspection is read-only; kill, renice, service control, hub federation and clustering are outside this release. Missing readings remain unavailable, and stale data retains its freshness status.
32
+ ## Use it
28
33
 
29
- [Installation and hardware](docs/installation.md) · [Operations and recovery](docs/operations.md) · [Release notes](CHANGELOG.md) · [Development](docs/development.md) · [Releasing and verification](docs/releasing.md) · [Architecture](ARCHITECTURE.md) · [Design](DESIGN.md)
34
+ | Task | Command or guide |
35
+ | --- | --- |
36
+ | Check services and the dashboard URL | `rigscope status` |
37
+ | Follow hub logs | `rigscope logs hub --follow` |
38
+ | Upgrade from npm | `rigscope upgrade` |
39
+ | Stop or start the installation | `rigscope stop` / `rigscope start` |
40
+ | Open the dashboard through Tailscale HTTPS | [Set up remote access](docs/installation.md#access-from-another-computer) |
41
+ | Monitor another machine | [Add a collector](docs/installation.md#add-machines-and-hubs) |
42
+ | Install a downloaded package | [Install from an archive](docs/installation.md#install-from-an-archive) |
30
43
 
31
- [Bottleneck readings](docs/bottlenecks.md) explains optional sensors and their limits. [Exports](docs/exports.md) describes visible-data CSV/JSON downloads. [Scale validation](docs/scale-validation.md) records synthetic workloads on one host; it is not a capacity guarantee.
44
+ Each collector connects outbound to up to eight hubs. Each hub has its own users,
45
+ permissions, history and alerts. Collectors need no incoming ports.
32
46
 
33
- Maintained by [Triet (@Triet1402)](https://github.com/Triet1402). Licensed under [MIT](LICENSE); dependency attribution is in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). See [SECURITY.md](SECURITY.md) to report vulnerabilities privately.
47
+ ## What to expect
34
48
 
35
- ## Advanced configuration
49
+ Rigscope is read-only: it does not kill processes, change priorities or control
50
+ services on monitored machines. Missing sensor readings stay unavailable.
51
+ NVIDIA and available AMD GPU counters are supported; Intel GPU readings are
52
+ partial. See the [hardware notes](docs/installation.md#hardware).
36
53
 
37
- Managed installations use `rigscope config` and private settings described in
38
- [installation](docs/installation.md#hub-configuration). The environment variables
39
- below apply to source development and raw hub/collector services; setting them in
40
- your shell does not reconfigure a managed service.
54
+ History is stored in SQLite. Process details are fetched while you view them and
55
+ are never saved to History. See [Monitoring and alerts](docs/monitoring.md) for
56
+ retention, sharing, freshness and notification behavior.
41
57
 
42
- Keep state/configuration directories 0700 and files 0600. Do not commit them.
58
+ ## Documentation
43
59
 
44
- | Hub variable | Behavior |
45
- | --- | --- |
46
- | `HUB_HOST`, `HUB_PORT` | Loopback-only listener; defaults `127.0.0.1:8081`. Port `0` is useful for isolated tests. |
47
- | `HUB_PUBLIC_ORIGIN`, `HUB_SOCKET_PATH` | Required together for remote mode. Exact HTTPS origin and private absolute Unix socket. No TCP listener in this mode. |
48
- | `HUB_DATABASE_PATH` | Authoritative SQLite telemetry/users/alerts/collector registry. Defaults beside `HUB_STATE_FILE`, otherwise `$XDG_STATE_HOME/rigscope/hub/telemetry.sqlite` (falling back to `~/.local/state`). |
49
- | `HUB_BROWSER_USERS` | First-run bootstrap JSON: `{username,passwordHash,machineIds,admin?}`. Scope is `"*"` or a machine-ID array; `[]` grants no machine access. |
50
- | `HUB_ADMIN_USERS` | Comma-separated usernames explicitly elevated during first import. When absent, an existing bootstrap account named `owner` is migrated as administrator. Other users need an explicit `admin:true`. |
51
- | `HUB_COLLECTORS` | First-run bootstrap JSON: `{collectorId,machineId,token}`; bounded by JSON bytes rather than machine count. Credentials travel only in bearer headers. |
52
- | `HUB_MAX_COLLECTOR_CONNECTIONS` | Concurrent collector socket budget; defaults to 100. Positive integer; tune to measured deployment capacity. |
53
- | `HUB_STATE_FILE` | Private enrollment-file import source for existing installations; enables the enrollment endpoint. Preserve it with deployment configuration for recovery. |
54
- | `HUB_ENROLLMENT_GRANTS` | Bootstrap grants `{token,expiresAt}`; at most 15 minutes. Consumed grants remain consumed across migration/restart. |
55
-
56
- From a source checkout, generate salted scrypt hashes with
57
- `scripts/hash-browser-password.cjs`, which reads passwords from stdin. Managed
58
- installation generates the initial account automatically. Keep hashes private. The database imports existing
59
- users/credentials once; later configuration restarts do not overwrite managed users
60
- or resurrect revoked credentials. Administration changes apply to active sessions
61
- and collector connections. Existing owner passwords and scopes are preserved.
62
-
63
- | Collector variable | Behavior |
60
+ | Guide | Covers |
64
61
  | --- | --- |
65
- | `COLLECTOR_MODE` | `real` by default; `mock` is explicit synthetic telemetry and never scans real processes. |
66
- | `COLLECTOR_STATE_FILE` | Private persistent identity, enrolled destinations and pending enrollment recovery proof. Defaults under `$XDG_STATE_HOME/rigscope/collector.json`. |
67
- | `COLLECTOR_INTERVAL_MS` | Shared sampling cadence; defaults 1000 ms, minimum 100 ms. GPU polling has a 1-second local floor. |
68
- | `COLLECTOR_HUBS` | Optional explicit destinations `{url,token,sharing?,intervalMs?}`; at most eight. Otherwise use saved enrollment. |
69
- | `COLLECTOR_HOSTNAME` | Metadata only; real mode defaults to OS hostname. |
70
-
71
- Destination `sharing` accepts `cpu`, `memory`, `swap`, `gpus`, `disks`, `network`,
72
- `networkAddresses`, `processes`, `processArguments`. CPU/memory remain required when
73
- an object is supplied. Missing fields default to true, except swap follows memory
74
- and process arguments default false. Review local sharing before upgrading a
75
- restricted destination to broader metrics. Environment variables are never collected.
76
- Policy is applied before queueing, to restored pending metrics before sending, and
77
- to every process result separately for each hub.
78
-
79
- ## Source enrollment, rotation and replacement
80
-
81
- For a managed installation, use `rigscope connect` as described in
82
- [Add machines and hubs](docs/installation.md#add-machines-and-hubs). The following
83
- commands require a source checkout with development dependencies installed.
84
-
85
- Create a short-lived grant through an authorized administration flow. On the machine,
86
- set `COLLECTOR_ENROLL_URL` to its full `ws[s]://…/api/collector/connect` URL and
87
- `COLLECTOR_ENROLL_TOKEN` privately, then run:
88
-
89
- ```sh
90
- npm run collector:enroll
91
- ```
92
-
93
- The collector saves a random recovery proof before requesting a credential. A retry
94
- after a lost successful response recovers the same credential using that proof;
95
- collector ID or hostname alone is insufficient. Restart the collector to apply changes.
96
-
97
- Rotation/replacement requires a grant explicitly bound to the existing hub-local
98
- machine mapping. Use `npm run collector:enroll -- --replace-enrollment` to replace a
99
- saved destination. Revocation invalidates open connections and old recovery proofs.
100
- Replacement never matches a machine by hostname or address.
101
-
102
- ## Monitoring behavior and bounds
103
-
104
- - Samples are acknowledged only after a durable SQLite commit. Retries deduplicate
105
- by collector/run/sequence. Replay fills History without replacing live state or
106
- triggering historical threshold incidents.
107
- - Per-destination outboxes retain pending metrics across collector restart, prioritize
108
- live telemetry, and bound replay/in-flight work. Defaults: ten minutes or 64 MiB
109
- of queued JSON per destination, 256 MiB aggregate queued JSON. Separate physical
110
- budgets count main database files plus WAL: 80 MiB per destination and 640 MiB
111
- across eight destinations. SQLite page caps, bounded writes, checkpoints and
112
- pressure rejection enforce these budgets; they are not OS filesystem quotas.
113
- - History defaults: raw 48 hours, one-minute rollups 30 days, one-hour rollups 400 days.
114
- Rollups preserve minima/maxima. Queries have point, series, scanned-row and elapsed
115
- budgets; partial results are disclosed. The hub defaults to a 2 GiB physical
116
- database/WAL budget shared by telemetry, users, enrollment and alerts. Retention
117
- protects the newest hour; when it cannot reclaim enough space, ingestion returns
118
- busy without acknowledging records. Existing oversized databases enter pressure
119
- mode; they are not destructively vacuumed at startup. Atomic writes may briefly
120
- grow WAL before checkpointing; blocked checkpoints surface pressure and stop
121
- subsequent ingestion rather than permitting continued growth.
122
- - Receipt freshness is `max(15 seconds, 3 × expected delivery interval)`. Unknown cadence
123
- uses a disclosed 15-second fallback. Connection state, collection availability and
124
- clock skew remain separate. Browser/hub clocks are not calibrated.
125
- - Process detail uses renewable viewer interests and one shared collector scan. Pausing,
126
- hiding/closing a view, session termination or lease expiry releases extra work.
127
- Process detail is never persisted. CPU is 100% per core; machine CPU is normalized
128
- across logical cores. Missing/inaccessible readings remain unavailable.
129
- - User sessions are in memory with a fixed twelve-hour lifetime; a hub restart requires
130
- signing in again. Users/scopes/password hashes and collector credentials persist.
131
- - Physical checks cover the Ubuntu RTX 3090 rig and the laptop’s RTX 5060 plus Radeon
132
- 860M iGPU. Intel sensor and ARM/RISC-V naming paths have deterministic fixture coverage;
133
- physical validation for those paths remains outstanding. See the [hardware support notes](docs/installation.md#hardware).
134
- - There is no fixed machine-count limit. The default concurrent collector connection
135
- budget is 100; [scale validation](docs/scale-validation.md) records synthetic
136
- workloads up to 75 machines on one host and is not a capacity guarantee.
137
- Remote kill/renice, service control, hub federation and clustering are out
138
- of scope for this read-only release.
139
-
140
- ## Alerts and administration
141
-
142
- Administration requires an explicit administrator role as well as machine scope.
143
- Use it to manage accounts/scopes, display names/tags, collector revocation and
144
- short-lived enrollment/replacement grants. User changes revoke existing browser
145
- sessions; credential changes close invalid collector connections. Wildcard scope
146
- alone does not grant administration.
147
-
148
- Alerts support above/below thresholds, duration, unavailable readings, missing
149
- receipts, maintenance and recovery. Value, unavailable and stale-receipt rules
150
- apply to every machine the hub tracks. Replay never opens historical incidents.
151
- Configure one HTTPS webhook channel in Alerts (loopback HTTP only for controlled
152
- test sinks). URL, headers and HMAC secret are write-only. Delivery is at-least-once:
153
- receivers should deduplicate the `Idempotency-Key`. Six attempts, a five-second
154
- request deadline and bounded persistent queues prevent unbounded delivery work.
155
-
156
- See [operations](docs/operations.md) for packaging, private service configuration,
157
- boot enablement, backups, tested restores, upgrades/rollback and measurements.
158
- The managed installer starts services by default; low-level archive tools print service commands for explicit execution.
62
+ | [Installation](docs/installation.md) | npm, HTTPS, collectors, upgrades and hardware |
63
+ | [Operations](docs/operations.md) | Diagnostics, backups, recovery and archive deployment |
64
+ | [System installation](docs/system-installation.md) | Dedicated service accounts and system units |
65
+ | [Configuration reference](docs/configuration.md) | Environment variables and source enrollment |
66
+ | [Monitoring and alerts](docs/monitoring.md) | Data limits, sharing, users and webhooks |
67
+ | [Sensor readings](docs/bottlenecks.md) / [Exports](docs/exports.md) | Reading meanings and downloads |
68
+ | [Development](docs/development.md) / [Architecture](ARCHITECTURE.md) / [Design](DESIGN.md) | Source setup and implementation references |
69
+ | [Releasing](docs/releasing.md) / [Release notes](CHANGELOG.md) | Publishing checks and version changes |
70
+ | [Scale validation](docs/scale-validation.md) | Synthetic measurements on one host; no capacity guarantee |
71
+
72
+ Published on [npm](https://www.npmjs.com/package/rigscope).
73
+ Maintained by [Triet (@Triet1402)](https://github.com/Triet1402).
74
+ Licensed under [MIT](LICENSE); see [dependency notices](THIRD_PARTY_NOTICES.md).
75
+ Report vulnerabilities privately using [SECURITY.md](SECURITY.md).
@@ -5292,7 +5292,7 @@ function budget(value, fallback) {
5292
5292
  // package.json
5293
5293
  var package_default = {
5294
5294
  name: "rigscope",
5295
- version: "0.1.0",
5295
+ version: "0.1.2",
5296
5296
  rigscopeConfigVersion: 2,
5297
5297
  private: false,
5298
5298
  engines: {
@@ -5360,6 +5360,9 @@ var package_default = {
5360
5360
  "README.md",
5361
5361
  "CHANGELOG.md",
5362
5362
  "docs/installation.md",
5363
+ "docs/system-installation.md",
5364
+ "docs/configuration.md",
5365
+ "docs/monitoring.md",
5363
5366
  "docs/operations.md",
5364
5367
  "docs/bottlenecks.md",
5365
5368
  "docs/exports.md",
@@ -5368,6 +5371,11 @@ var package_default = {
5368
5371
  "docs/scale-validation.md",
5369
5372
  "docs/scale-validation.json",
5370
5373
  "docs/scale-acceptance.json",
5374
+ "docs/stress-2026-11-04/README.md",
5375
+ "docs/stress-2026-11-04/index.jsonl",
5376
+ "docs/stress-2026-11-04/manifest.json",
5377
+ "docs/stress-2026-11-04/results.html",
5378
+ "docs/stress-2026-11-04/*ms.json",
5371
5379
  "ARCHITECTURE.md",
5372
5380
  "DESIGN.md",
5373
5381
  "LICENSE",
package/dist/hub.cjs CHANGED
@@ -1741,7 +1741,7 @@ function describeError(error) {
1741
1741
  // package.json
1742
1742
  var package_default = {
1743
1743
  name: "rigscope",
1744
- version: "0.1.0",
1744
+ version: "0.1.2",
1745
1745
  rigscopeConfigVersion: 2,
1746
1746
  private: false,
1747
1747
  engines: {
@@ -1809,6 +1809,9 @@ var package_default = {
1809
1809
  "README.md",
1810
1810
  "CHANGELOG.md",
1811
1811
  "docs/installation.md",
1812
+ "docs/system-installation.md",
1813
+ "docs/configuration.md",
1814
+ "docs/monitoring.md",
1812
1815
  "docs/operations.md",
1813
1816
  "docs/bottlenecks.md",
1814
1817
  "docs/exports.md",
@@ -1817,6 +1820,11 @@ var package_default = {
1817
1820
  "docs/scale-validation.md",
1818
1821
  "docs/scale-validation.json",
1819
1822
  "docs/scale-acceptance.json",
1823
+ "docs/stress-2026-11-04/README.md",
1824
+ "docs/stress-2026-11-04/index.jsonl",
1825
+ "docs/stress-2026-11-04/manifest.json",
1826
+ "docs/stress-2026-11-04/results.html",
1827
+ "docs/stress-2026-11-04/*ms.json",
1820
1828
  "ARCHITECTURE.md",
1821
1829
  "DESIGN.md",
1822
1830
  "LICENSE",
@@ -4054,7 +4062,8 @@ function queryHistory(db, q, budget = {}) {
4054
4062
  seriesRows = seriesRows.slice(0, Math.max(0, chosen.cutSeries));
4055
4063
  truncated = true;
4056
4064
  }
4057
- const stepMs = Math.max(chosen.resolutionMs, Math.ceil(rangeMs / maxPoints));
4065
+ const stepMs = Math.max(1, Math.ceil(rangeMs / maxPoints / chosen.resolutionMs)) * chosen.resolutionMs;
4066
+ const originMs = Math.floor(q.fromMs / stepMs) * stepMs;
4058
4067
  const series = [];
4059
4068
  for (const row of seriesRows) {
4060
4069
  if (performance.now() - started > maxElapsedMs) {
@@ -4070,7 +4079,7 @@ function queryHistory(db, q, budget = {}) {
4070
4079
  Number(row.series_id),
4071
4080
  fromBucketMs(chosen.tier, q.fromMs),
4072
4081
  q.toMs,
4073
- q.fromMs,
4082
+ originMs,
4074
4083
  stepMs,
4075
4084
  // An additional per-series guard. Tier selection already keeps the total
4076
4085
  // under budget; this makes a single query bounded even if a custom
@@ -4236,8 +4245,8 @@ function readGaps(db, machineId, fromMs, toMs) {
4236
4245
  "SELECT from_ms, to_ms, dropped, reason FROM gaps WHERE machine_id = ? AND to_ms >= ? AND from_ms <= ? ORDER BY from_ms LIMIT ?"
4237
4246
  ).all(machineId, fromMs, toMs, MAX_GAPS);
4238
4247
  const missing = db.db.prepare(
4239
- "WITH ordered AS ( SELECT captured_at_ms, LAG(captured_at_ms) OVER (PARTITION BY machine_id ORDER BY captured_at_ms) AS prev_ms, expected_interval_ms FROM sample_receipts WHERE machine_id = ? AND captured_at_ms >= ? AND captured_at_ms <= ? ) SELECT prev_ms AS from_ms, captured_at_ms AS to_ms FROM ordered WHERE prev_ms IS NOT NULL AND captured_at_ms - prev_ms > MAX(15000, 3 * COALESCE(expected_interval_ms, 5000)) ORDER BY captured_at_ms LIMIT ?"
4240
- ).all(machineId, fromMs, toMs, MAX_GAPS);
4248
+ "WITH before_window AS ( SELECT captured_at_ms, expected_interval_ms FROM sample_receipts WHERE machine_id = ? AND captured_at_ms < ? ORDER BY captured_at_ms DESC LIMIT 1 ), in_window AS ( SELECT captured_at_ms, expected_interval_ms FROM sample_receipts WHERE machine_id = ? AND captured_at_ms >= ? AND captured_at_ms <= ? ), ordered AS ( SELECT captured_at_ms, expected_interval_ms, LAG(captured_at_ms) OVER (ORDER BY captured_at_ms) AS prev_ms FROM (SELECT * FROM before_window UNION ALL SELECT * FROM in_window) ) SELECT MAX(prev_ms, ?) AS from_ms, captured_at_ms AS to_ms FROM ordered WHERE prev_ms IS NOT NULL AND captured_at_ms > ? AND captured_at_ms - prev_ms > MAX(15000, 3 * COALESCE(expected_interval_ms, 5000)) ORDER BY captured_at_ms LIMIT ?"
4249
+ ).all(machineId, fromMs, machineId, fromMs, toMs, fromMs, fromMs, MAX_GAPS);
4241
4250
  const gaps = [
4242
4251
  ...dropped.map((row) => ({
4243
4252
  fromMs: Number(row.from_ms),
package/dist/ops.cjs CHANGED
@@ -1559,6 +1559,9 @@ var PACKAGE_TOP_LEVEL = /* @__PURE__ */ new Set([
1559
1559
  ]);
1560
1560
  var PACKAGE_DOCS = /* @__PURE__ */ new Set([
1561
1561
  "docs/installation.md",
1562
+ "docs/system-installation.md",
1563
+ "docs/configuration.md",
1564
+ "docs/monitoring.md",
1562
1565
  "docs/operations.md",
1563
1566
  "docs/development.md",
1564
1567
  "docs/releasing.md",
@@ -4080,7 +4083,8 @@ function queryHistory(db, q, budget = {}) {
4080
4083
  seriesRows = seriesRows.slice(0, Math.max(0, chosen.cutSeries));
4081
4084
  truncated = true;
4082
4085
  }
4083
- const stepMs = Math.max(chosen.resolutionMs, Math.ceil(rangeMs / maxPoints));
4086
+ const stepMs = Math.max(1, Math.ceil(rangeMs / maxPoints / chosen.resolutionMs)) * chosen.resolutionMs;
4087
+ const originMs = Math.floor(q.fromMs / stepMs) * stepMs;
4084
4088
  const series = [];
4085
4089
  for (const row of seriesRows) {
4086
4090
  if (performance.now() - started > maxElapsedMs) {
@@ -4096,7 +4100,7 @@ function queryHistory(db, q, budget = {}) {
4096
4100
  Number(row.series_id),
4097
4101
  fromBucketMs(chosen.tier, q.fromMs),
4098
4102
  q.toMs,
4099
- q.fromMs,
4103
+ originMs,
4100
4104
  stepMs,
4101
4105
  // An additional per-series guard. Tier selection already keeps the total
4102
4106
  // under budget; this makes a single query bounded even if a custom
@@ -4262,8 +4266,8 @@ function readGaps(db, machineId, fromMs, toMs) {
4262
4266
  "SELECT from_ms, to_ms, dropped, reason FROM gaps WHERE machine_id = ? AND to_ms >= ? AND from_ms <= ? ORDER BY from_ms LIMIT ?"
4263
4267
  ).all(machineId, fromMs, toMs, MAX_GAPS);
4264
4268
  const missing = db.db.prepare(
4265
- "WITH ordered AS ( SELECT captured_at_ms, LAG(captured_at_ms) OVER (PARTITION BY machine_id ORDER BY captured_at_ms) AS prev_ms, expected_interval_ms FROM sample_receipts WHERE machine_id = ? AND captured_at_ms >= ? AND captured_at_ms <= ? ) SELECT prev_ms AS from_ms, captured_at_ms AS to_ms FROM ordered WHERE prev_ms IS NOT NULL AND captured_at_ms - prev_ms > MAX(15000, 3 * COALESCE(expected_interval_ms, 5000)) ORDER BY captured_at_ms LIMIT ?"
4266
- ).all(machineId, fromMs, toMs, MAX_GAPS);
4269
+ "WITH before_window AS ( SELECT captured_at_ms, expected_interval_ms FROM sample_receipts WHERE machine_id = ? AND captured_at_ms < ? ORDER BY captured_at_ms DESC LIMIT 1 ), in_window AS ( SELECT captured_at_ms, expected_interval_ms FROM sample_receipts WHERE machine_id = ? AND captured_at_ms >= ? AND captured_at_ms <= ? ), ordered AS ( SELECT captured_at_ms, expected_interval_ms, LAG(captured_at_ms) OVER (ORDER BY captured_at_ms) AS prev_ms FROM (SELECT * FROM before_window UNION ALL SELECT * FROM in_window) ) SELECT MAX(prev_ms, ?) AS from_ms, captured_at_ms AS to_ms FROM ordered WHERE prev_ms IS NOT NULL AND captured_at_ms > ? AND captured_at_ms - prev_ms > MAX(15000, 3 * COALESCE(expected_interval_ms, 5000)) ORDER BY captured_at_ms LIMIT ?"
4270
+ ).all(machineId, fromMs, machineId, fromMs, toMs, fromMs, fromMs, MAX_GAPS);
4267
4271
  const gaps = [
4268
4272
  ...dropped.map((row) => ({
4269
4273
  fromMs: Number(row.from_ms),
@@ -27,7 +27,7 @@ CPU temperature supports known CPU hwmon drivers, including `coretemp` and
27
27
  `k10temp`. CPU package power uses the Linux powercap `intel-rapl:N` interface,
28
28
  including compatible AMD implementations. Many systems restrict `energy_uj` to
29
29
  root. The collector remains unprivileged. The optional
30
- [system installer](installation.md#system-installation) grants its dedicated account persistent
30
+ [system installer](system-installation.md#cpu-package-power) grants its dedicated account persistent
31
31
  read-only package-counter access; ordinary user installation leaves permissions
32
32
  under the operator's control.
33
33
 
@@ -0,0 +1,85 @@
1
+ # Configuration reference
2
+
3
+ For an installation made with `rigscope install`, use `rigscope config` to find
4
+ its private settings. See [Hub configuration](installation.md#hub-configuration)
5
+ and [Remote access](installation.md#access-from-another-computer) for managed setup.
6
+
7
+ The environment variables below apply to source development and services that
8
+ run the hub or collector directly. Setting them in your shell does not change
9
+ an installed background service. Keep private directories at mode `0700` and
10
+ configuration files at `0600`; do not commit them.
11
+
12
+ ## Hub variables
13
+
14
+ | Variable | Purpose and default |
15
+ | --- | --- |
16
+ | `HUB_HOST`, `HUB_PORT` | Local listener: `127.0.0.1:8081`. Only literal loopback addresses are accepted. Port `0` selects an unused port for tests. |
17
+ | `HUB_PUBLIC_ORIGIN`, `HUB_SOCKET_PATH` | Remote access: set both the exact HTTPS origin and an absolute Unix socket path in a private directory. The hub then has no TCP listener. |
18
+ | `HUB_DATABASE_PATH` | SQLite database for telemetry, users, alerts and the collector registry. Defaults beside `HUB_STATE_FILE`, or under `$XDG_STATE_HOME/rigscope/hub/` (falling back to `~/.local/state`). |
19
+ | `HUB_BROWSER_USERS` | First-run users as JSON: `{username,passwordHash,machineIds,admin?}`. `machineIds` is `"*"` or a list; `[]` allows no machines. |
20
+ | `HUB_ADMIN_USERS` | Comma-separated usernames to make administrators during first import. If omitted, an existing bootstrap account named `owner` becomes an administrator. Other users need an explicit `admin:true`. |
21
+ | `HUB_COLLECTORS` | First-run collector credentials as JSON: `{collectorId,machineId,token}`. The limit applies to JSON bytes, not a fixed machine count. |
22
+ | `HUB_MAX_COLLECTOR_CONNECTIONS` | Maximum concurrent collector connections. Positive integer; defaults to `100`. Choose a value based on measured capacity. |
23
+ | `HUB_STATE_FILE` | Private enrollment file to import from an existing installation; also enables enrollment. Keep it with the deployment configuration for recovery. |
24
+ | `HUB_ENROLLMENT_GRANTS` | Initial grants as JSON: `{token,expiresAt}`. Expiry must be within 15 minutes. Used grants stay consumed after import and restart. |
25
+
26
+ ### First-run users and credentials
27
+
28
+ The database imports bootstrap users and collector credentials once. Later
29
+ restarts do not overwrite managed users or restore revoked credentials. Use
30
+ **Administration** to change users after the first start.
31
+
32
+ The managed installer creates the initial account for you. From a source
33
+ checkout, use `scripts/hash-browser-password.cjs` to generate salted scrypt
34
+ hashes; it reads passwords from stdin. Keep hashes private.
35
+
36
+ ## Collector variables
37
+
38
+ | Variable | Purpose and default |
39
+ | --- | --- |
40
+ | `COLLECTOR_MODE` | `real` by default. `mock` generates synthetic readings and never scans real processes. |
41
+ | `COLLECTOR_STATE_FILE` | Private saved identity, destinations and enrollment recovery proof. Defaults to `$XDG_STATE_HOME/rigscope/collector.json` (falling back to `~/.local/state`). |
42
+ | `COLLECTOR_INTERVAL_MS` | Sampling interval: `1000` ms by default, minimum `100` ms. GPU polling runs at most once per second. |
43
+ | `COLLECTOR_HUBS` | Explicit destinations as JSON: `{url,token,sharing?,intervalMs?}`, up to eight. Otherwise the collector uses saved enrollment. |
44
+ | `COLLECTOR_HOSTNAME` | Display metadata; defaults to the OS hostname in real mode. |
45
+
46
+ ### Sharing settings
47
+
48
+ Each destination's `sharing` object accepts `cpu`, `memory`, `swap`, `gpus`,
49
+ `disks`, `network`, `networkAddresses`, `processes` and `processArguments`.
50
+ When supplying an object, CPU and memory must remain enabled.
51
+
52
+ Omitted fields default to true, except `swap` follows `memory` and
53
+ `processArguments` defaults to false. Managed enrollment starts with network
54
+ addresses and full process arguments disabled. Review a destination's saved
55
+ policy before expanding what it shares. Environment variables are never collected.
56
+
57
+ The collector applies sharing rules before queueing samples, again before
58
+ sending restored samples, and to each hub's process results. Restricting a policy
59
+ also restricts pending records.
60
+
61
+ ## Source enrollment, rotation and replacement
62
+
63
+ For a managed installation, follow [Add machines and hubs](installation.md#add-machines-and-hubs)
64
+ using `rigscope connect`. The steps here require a source checkout with
65
+ development dependencies installed.
66
+
67
+ 1. Create a short-lived grant through the hub's administration interface.
68
+ 2. Set `COLLECTOR_ENROLL_URL` to the full `ws[s]://…/api/collector/connect` URL.
69
+ Set `COLLECTOR_ENROLL_TOKEN` privately to the grant.
70
+ 3. Run:
71
+
72
+ ```sh
73
+ npm run collector:enroll
74
+ ```
75
+
76
+ 4. Remove the grant from the environment and restart the collector.
77
+
78
+ The collector saves a random recovery proof before enrolling. If a successful
79
+ response is lost, retrying with that proof recovers the same credential. A
80
+ hostname or collector ID alone cannot recover it.
81
+
82
+ Rotation or replacement needs a grant bound to the existing machine on that
83
+ hub. Use `npm run collector:enroll -- --replace-enrollment` to replace a saved
84
+ destination. Revocation closes existing connections and invalidates old recovery
85
+ proofs. Replacement never identifies a machine by its hostname or address.
@@ -16,7 +16,7 @@ npm start
16
16
  npm run collector:start
17
17
  ```
18
18
 
19
- `npm run collector:enroll` uses `COLLECTOR_ENROLL_URL` and a private `COLLECTOR_ENROLL_TOKEN`. `npm run collector:mock` emits synthetic readings. Real collection continues without a browser. See the README for configuration and destination sharing policy.
19
+ `npm run collector:enroll` uses `COLLECTOR_ENROLL_URL` and a private `COLLECTOR_ENROLL_TOKEN`. `npm run collector:mock` emits synthetic readings. Real collection continues without a browser. See the [configuration reference](configuration.md) for variables, enrollment and sharing settings.
20
20
 
21
21
  ## HTTPS boundary
22
22