rigscope 0.2.0 → 0.2.1

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 (85) 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 +1 -1
  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 +1 -1
  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 +1 -1
  27. package/.next/server/app/alerts.segments/alerts/__PAGE__.segment.rsc +2 -2
  28. package/.next/server/app/connections/page.js +1 -1
  29. package/.next/server/app/connections/page_client-reference-manifest.js +1 -1
  30. package/.next/server/app/connections.html +1 -1
  31. package/.next/server/app/connections.rsc +3 -3
  32. package/.next/server/app/connections.segments/_full.segment.rsc +3 -3
  33. package/.next/server/app/connections.segments/_tree.segment.rsc +1 -1
  34. package/.next/server/app/connections.segments/connections/__PAGE__.segment.rsc +3 -3
  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 +2 -2
  38. package/.next/server/app/history.segments/_full.segment.rsc +2 -2
  39. package/.next/server/app/history.segments/_tree.segment.rsc +1 -1
  40. package/.next/server/app/history.segments/history/__PAGE__.segment.rsc +2 -2
  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 +1 -1
  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 +1 -1
  51. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
  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_client-reference-manifest.js +1 -1
  55. package/.next/server/app/processes.html +1 -1
  56. package/.next/server/app/processes.rsc +2 -2
  57. package/.next/server/app/processes.segments/_full.segment.rsc +2 -2
  58. package/.next/server/app/processes.segments/_tree.segment.rsc +1 -1
  59. package/.next/server/app/processes.segments/processes/__PAGE__.segment.rsc +2 -2
  60. package/.next/server/app-paths-manifest.json +2 -2
  61. package/.next/server/chunks/161.js +1 -1
  62. package/.next/server/middleware-build-manifest.js +1 -1
  63. package/.next/server/pages/404.html +1 -1
  64. package/.next/server/pages/500.html +1 -1
  65. package/.next/static/chunks/939-92930fde48061e20.js +1 -0
  66. package/.next/static/chunks/app/connections/page-7d18b901f2338f20.js +1 -0
  67. package/ARCHITECTURE.md +18 -6
  68. package/CHANGELOG.md +35 -0
  69. package/dist/cli.cjs +762 -509
  70. package/dist/collector.cjs +581 -115
  71. package/dist/hub.cjs +7 -3
  72. package/dist/system.cjs +1257 -363
  73. package/docs/configuration.md +1 -0
  74. package/docs/installation.md +9 -3
  75. package/docs/monitoring.md +6 -3
  76. package/docs/operations.md +40 -13
  77. package/docs/system-installation.md +11 -4
  78. package/docs/telemetry-storage.md +80 -9
  79. package/package.json +1 -1
  80. package/packaging/collector.env.example +6 -0
  81. package/packaging/system/rigscope-collector.service.example +3 -0
  82. package/.next/static/chunks/939-514e554087419c71.js +0 -1
  83. package/.next/static/chunks/app/connections/page-75abd16fc495fcbd.js +0 -1
  84. /package/.next/static/{Jlbibe2_iFCljUO4-BUK7 → JbaLjudQSxrMUD_VHPrnD}/_buildManifest.js +0 -0
  85. /package/.next/static/{Jlbibe2_iFCljUO4-BUK7 → JbaLjudQSxrMUD_VHPrnD}/_ssgManifest.js +0 -0
package/dist/cli.cjs CHANGED
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  ));
24
24
 
25
25
  // src/cli/main.ts
26
- var import_node_fs19 = require("node:fs");
27
- var import_node_path20 = require("node:path");
26
+ var import_node_fs20 = require("node:fs");
27
+ var import_node_path21 = require("node:path");
28
28
  var import_node_util2 = require("node:util");
29
29
  var import_node_readline = require("node:readline");
30
30
  var import_node_stream = require("node:stream");
@@ -42,6 +42,9 @@ var SHARING_KEYS = [
42
42
  "processArguments"
43
43
  ];
44
44
 
45
+ // collector/destinations/queue.ts
46
+ var DEFAULT_COLLECTOR_QUEUE_MODE = "memory";
47
+
45
48
  // collector/config.ts
46
49
  var ConfigError = class extends Error {
47
50
  issues;
@@ -247,6 +250,18 @@ function parseDestinations(env, issues, destinations) {
247
250
  }
248
251
  }
249
252
  }
253
+ var QUEUE_MODES = ["memory", "durable"];
254
+ function parseQueueMode(env, issues) {
255
+ const raw = env["COLLECTOR_QUEUE_MODE"]?.trim();
256
+ if (raw === void 0 || raw === "") {
257
+ return DEFAULT_COLLECTOR_QUEUE_MODE;
258
+ }
259
+ if (!QUEUE_MODES.includes(raw)) {
260
+ issues.push(`COLLECTOR_QUEUE_MODE must be one of ${QUEUE_MODES.join(" or ")}`);
261
+ return DEFAULT_COLLECTOR_QUEUE_MODE;
262
+ }
263
+ return raw;
264
+ }
250
265
  function parseIntervalMs(env, issues) {
251
266
  const raw = env["COLLECTOR_INTERVAL_MS"]?.trim();
252
267
  if (raw === void 0 || raw === "") {
@@ -277,6 +292,7 @@ function parseCollectorConfig(env) {
277
292
  }
278
293
  const destinations = [];
279
294
  const intervalMs = parseIntervalMs(env, issues);
295
+ const queueMode = parseQueueMode(env, issues);
280
296
  parseDestinations(env, issues, destinations);
281
297
  if (issues.length > 0) {
282
298
  throw new ConfigError(issues);
@@ -286,7 +302,8 @@ function parseCollectorConfig(env) {
286
302
  hostname,
287
303
  hostnameIsMockDefault: rawHostname === "",
288
304
  intervalMs,
289
- destinations
305
+ destinations,
306
+ queueMode
290
307
  };
291
308
  }
292
309
 
@@ -3624,17 +3641,17 @@ function uninstallInstallation(dir, purge = true, injected = {}) {
3624
3641
 
3625
3642
  // src/cli/mutation.ts
3626
3643
  var import_node_child_process3 = require("node:child_process");
3627
- var import_node_fs13 = require("node:fs");
3628
- var import_node_path14 = require("node:path");
3644
+ var import_node_fs14 = require("node:fs");
3645
+ var import_node_path15 = require("node:path");
3629
3646
  var import_promises = require("node:readline/promises");
3630
3647
 
3631
3648
  // src/cli/lifecycle.ts
3632
- var import_node_fs12 = require("node:fs");
3633
- var import_node_path13 = require("node:path");
3649
+ var import_node_fs13 = require("node:fs");
3650
+ var import_node_path14 = require("node:path");
3634
3651
 
3635
3652
  // src/cli/upgrade.ts
3636
- var import_node_fs11 = require("node:fs");
3637
- var import_node_path12 = require("node:path");
3653
+ var import_node_fs12 = require("node:fs");
3654
+ var import_node_path13 = require("node:path");
3638
3655
 
3639
3656
  // src/operations/database.ts
3640
3657
  var import_node_fs10 = require("node:fs");
@@ -3982,6 +3999,187 @@ async function restoreDatabase(options) {
3982
3999
  throw error2;
3983
4000
  }
3984
4001
  }
4002
+ var MACHINE_HISTORY_TABLES = [
4003
+ "points_raw",
4004
+ "points_10s",
4005
+ "points_1m",
4006
+ "points_1h",
4007
+ "sample_receipts",
4008
+ "gaps",
4009
+ "machine_latest",
4010
+ "inventory",
4011
+ "alert_observed_resources",
4012
+ "alert_machine_progress",
4013
+ "alert_incidents",
4014
+ "series"
4015
+ ];
4016
+ function clearMachineHistory(database) {
4017
+ const path2 = resolvePath(database, "database");
4018
+ if (!(0, import_node_fs10.existsSync)(path2)) return { deleted: {}, integrity: "absent" };
4019
+ assertPrivateRegularFile(path2, "database");
4020
+ assertNoActiveHubLock(path2);
4021
+ const db = new import_node_sqlite2.DatabaseSync(path2, { timeout: BUSY_TIMEOUT_MS2 });
4022
+ const deleted = {};
4023
+ try {
4024
+ db.exec("PRAGMA busy_timeout = 5000");
4025
+ const present = new Set(
4026
+ db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => row.name)
4027
+ );
4028
+ db.exec("BEGIN IMMEDIATE");
4029
+ try {
4030
+ for (const table of MACHINE_HISTORY_TABLES) {
4031
+ if (!present.has(table)) continue;
4032
+ const result = db.prepare(`DELETE FROM ${table}`).run();
4033
+ deleted[table] = Number(result.changes);
4034
+ }
4035
+ db.exec("COMMIT");
4036
+ } catch (error2) {
4037
+ try {
4038
+ db.exec("ROLLBACK");
4039
+ } catch {
4040
+ }
4041
+ throw error2;
4042
+ }
4043
+ const autoVacuum = db.prepare("PRAGMA auto_vacuum").get();
4044
+ if (autoVacuum && Object.values(autoVacuum)[0] === 2) db.exec("PRAGMA incremental_vacuum(1024)");
4045
+ try {
4046
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
4047
+ } catch {
4048
+ }
4049
+ } finally {
4050
+ db.close();
4051
+ }
4052
+ return { deleted, integrity: inspectDatabase(path2).integrity };
4053
+ }
4054
+
4055
+ // src/cli/machine-transition.ts
4056
+ var import_node_fs11 = require("node:fs");
4057
+ var import_node_path12 = require("node:path");
4058
+ var import_node_crypto11 = require("node:crypto");
4059
+ var MACHINE_DATA_TRANSITION_FILE = "machine-data-transition.json";
4060
+ var STAGED_QUEUE_PREFIX = "outbox.pre-transition-";
4061
+ function machineDataTransitionPath(stateRoot) {
4062
+ return (0, import_node_path12.join)(stateRoot, MACHINE_DATA_TRANSITION_FILE);
4063
+ }
4064
+ function readMachineDataTransition(stateRoot) {
4065
+ const path2 = machineDataTransitionPath(stateRoot);
4066
+ try {
4067
+ const stat = (0, import_node_fs11.lstatSync)(path2);
4068
+ if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 63) !== 0) {
4069
+ throw new Error("marker must be a private regular file");
4070
+ }
4071
+ const value = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
4072
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("invalid marker");
4073
+ const record = value;
4074
+ if (typeof record.transitionedAt !== "string" || !Number.isFinite(Date.parse(record.transitionedAt))) {
4075
+ throw new Error("invalid transition date");
4076
+ }
4077
+ return { transitionedAt: record.transitionedAt, release: typeof record.release === "string" ? record.release : null };
4078
+ } catch (error2) {
4079
+ if (error2.code === "ENOENT") return null;
4080
+ throw new OperationsError(
4081
+ "invalid-transition-marker",
4082
+ `Cannot determine whether the one-time reset completed; preserving machine data. Repair ${path2}: ${errorMessage(error2)}`,
4083
+ { cause: error2 }
4084
+ );
4085
+ }
4086
+ }
4087
+ function recordMachineDataTransition(stateRoot, release, write = (path2, content) => writePrivateFile(path2, content)) {
4088
+ const marker = { transitionedAt: (/* @__PURE__ */ new Date()).toISOString(), release };
4089
+ write(machineDataTransitionPath(stateRoot), `${JSON.stringify(marker, null, 2)}
4090
+ `);
4091
+ }
4092
+ function newMachineDataCleanup(transitioned) {
4093
+ return {
4094
+ report: { transitioned, databaseRows: null, collectorQueuesRemoved: false, warning: null },
4095
+ stagedQueues: null,
4096
+ databaseCleared: false
4097
+ };
4098
+ }
4099
+ function performMachineDataCleanup(stateRoot, paths, now = Date.now, deps = {}) {
4100
+ if (readMachineDataTransition(stateRoot) !== null) return newMachineDataCleanup(false);
4101
+ const cleanup = newMachineDataCleanup(true);
4102
+ const clear = deps.clear ?? clearMachineHistory;
4103
+ const warnings = [];
4104
+ try {
4105
+ if ((0, import_node_fs11.existsSync)(paths.queueTree)) {
4106
+ const staged = (0, import_node_path12.join)((0, import_node_path12.dirname)(paths.queueTree), `${STAGED_QUEUE_PREFIX}${timestampSlug(now())}-${(0, import_node_crypto11.randomUUID)()}`);
4107
+ (0, import_node_fs11.renameSync)(paths.queueTree, staged);
4108
+ cleanup.stagedQueues = staged;
4109
+ cleanup.report.collectorQueuesRemoved = true;
4110
+ }
4111
+ } catch (error2) {
4112
+ warnings.push(`collector queues: ${errorMessage(error2)}`);
4113
+ }
4114
+ try {
4115
+ if ((0, import_node_fs11.existsSync)(paths.database)) {
4116
+ cleanup.databaseCleared = true;
4117
+ cleanup.report.databaseRows = clear(paths.database).deleted;
4118
+ }
4119
+ } catch (error2) {
4120
+ warnings.push(`hub database: ${errorMessage(error2)}`);
4121
+ }
4122
+ cleanup.report.warning = warnings.length > 0 ? warnings.join("; ") : null;
4123
+ return cleanup;
4124
+ }
4125
+ function undoMachineDataCleanup(paths, stagedQueues) {
4126
+ if (stagedQueues === null || !(0, import_node_fs11.existsSync)(stagedQueues)) return [];
4127
+ try {
4128
+ if ((0, import_node_fs11.existsSync)(paths.queueTree)) {
4129
+ const failedQueue = `${paths.queueTree}.failed-transition-${(0, import_node_crypto11.randomUUID)()}`;
4130
+ (0, import_node_fs11.renameSync)(paths.queueTree, failedQueue);
4131
+ try {
4132
+ (0, import_node_fs11.renameSync)(stagedQueues, paths.queueTree);
4133
+ } catch (error2) {
4134
+ (0, import_node_fs11.renameSync)(failedQueue, paths.queueTree);
4135
+ throw error2;
4136
+ }
4137
+ return [`restored the collector queue tree; replacement runtime queue preserved at ${failedQueue}`];
4138
+ }
4139
+ (0, import_node_fs11.renameSync)(stagedQueues, paths.queueTree);
4140
+ return ["restored the collector queue tree the transition had staged aside"];
4141
+ } catch (error2) {
4142
+ return [`machine data rollback could not restore the collector queue: ${errorMessage(error2)}`];
4143
+ }
4144
+ }
4145
+ function completeMachineDataCleanup(stateRoot, cleanup, release, write) {
4146
+ if (!cleanup.report.transitioned) return;
4147
+ if (cleanup.report.warning !== null) return;
4148
+ try {
4149
+ recordMachineDataTransition(stateRoot, release, write);
4150
+ } catch (error2) {
4151
+ cleanup.report.warning = `could not record transition completion: ${errorMessage(error2)}`;
4152
+ return;
4153
+ }
4154
+ if (cleanup.stagedQueues !== null) {
4155
+ try {
4156
+ (0, import_node_fs11.rmSync)(cleanup.stagedQueues, { recursive: true, force: true });
4157
+ } catch (error2) {
4158
+ cleanup.report.warning = `transition completed; staged queue remains at ${cleanup.stagedQueues}: ${errorMessage(error2)}`;
4159
+ }
4160
+ }
4161
+ }
4162
+ function machineDataReportRows(report) {
4163
+ if (report.databaseRows === null) return null;
4164
+ return Object.values(report.databaseRows).reduce((sum, rows) => sum + rows, 0);
4165
+ }
4166
+ function machineDataKeptNote() {
4167
+ return "accounts, sessions, enrollment and grants, settings, alert rules/jobs/webhook settings, machine names/tags and recordings were kept";
4168
+ }
4169
+ function describeMachineDataReport(report) {
4170
+ const summary = report.transitioned ? (() => {
4171
+ const rows = machineDataReportRows(report);
4172
+ const parts = [
4173
+ rows === null ? "no hub database" : `${rows} database row(s)`,
4174
+ ...report.collectorQueuesRemoved ? ["the collector queue tree"] : []
4175
+ ];
4176
+ return `Machine data: one-time RAM-first transition discarded ${parts.join(" and ")}. The ${machineDataKeptNote()}.`;
4177
+ })() : "Machine data: one-time transition already completed; durable history and collector queues preserved.";
4178
+ return {
4179
+ summary,
4180
+ warning: report.warning === null ? null : `Machine-data cleanup warning (${report.warning}). The upgrade is healthy; cleanup without a completion marker is retried on the next upgrade.`
4181
+ };
4182
+ }
3985
4183
 
3986
4184
  // src/cli/health.ts
3987
4185
  var import_node_http2 = require("node:http");
@@ -4175,6 +4373,7 @@ function dependencies(deps = {}) {
4175
4373
  restore: deps.restore ?? restoreDatabase,
4176
4374
  inspect: deps.inspect ?? inspectDatabase,
4177
4375
  inspectRuntime: deps.inspectRuntime ?? inspectDatabaseWithRuntime,
4376
+ clearHistory: deps.clearHistory ?? clearMachineHistory,
4178
4377
  waitHealth: deps.waitHealth ?? waitForHealth,
4179
4378
  activate: deps.activate ?? activatePackage,
4180
4379
  swap: deps.swap ?? swapRuntimes,
@@ -4185,10 +4384,10 @@ function dependencies(deps = {}) {
4185
4384
  function acquireInstallLocks(dir, acquireLease) {
4186
4385
  const releases = [];
4187
4386
  try {
4188
- releases.push(acquireLease((0, import_node_path12.join)(dir, "run", "hub.lock")));
4189
- releases.push(acquireLease((0, import_node_path12.join)(dir, "run", "collector.lock")));
4190
- releases.push(acquireLease((0, import_node_path12.join)(dir, "run", "rigscope.lock")));
4191
- releases.push(acquireLease((0, import_node_path12.join)(dir, "collector", "collector-runtime.lock")));
4387
+ releases.push(acquireLease((0, import_node_path13.join)(dir, "run", "hub.lock")));
4388
+ releases.push(acquireLease((0, import_node_path13.join)(dir, "run", "collector.lock")));
4389
+ releases.push(acquireLease((0, import_node_path13.join)(dir, "run", "rigscope.lock")));
4390
+ releases.push(acquireLease((0, import_node_path13.join)(dir, "collector", "collector-runtime.lock")));
4192
4391
  } catch (error2) {
4193
4392
  for (const release of releases.reverse()) {
4194
4393
  try {
@@ -4254,8 +4453,11 @@ function assertComponentsStopped(dir, deps, components) {
4254
4453
  }
4255
4454
  }
4256
4455
  }
4456
+ function machineDataPaths(dir) {
4457
+ return { database: databasePath(dir), queueTree: (0, import_node_path13.join)(dir, "collector", "outbox") };
4458
+ }
4257
4459
  function collectorStateCheck(dir) {
4258
- const path2 = (0, import_node_path12.join)(dir, "collector", "state.json");
4460
+ const path2 = (0, import_node_path13.join)(dir, "collector", "state.json");
4259
4461
  let raw;
4260
4462
  try {
4261
4463
  raw = readPrivate(path2);
@@ -4279,13 +4481,13 @@ function hubTarget(config, dir) {
4279
4481
  role: "hub",
4280
4482
  port: config.port,
4281
4483
  origin: config.origin,
4282
- socket: config.socket ?? (0, import_node_path12.join)(dir, "run", "hub.sock")
4484
+ socket: config.socket ?? (0, import_node_path13.join)(dir, "run", "hub.sock")
4283
4485
  });
4284
4486
  }
4285
4487
  async function verifyRunningInstallation(options) {
4286
4488
  const d = dependencies(options.deps);
4287
4489
  const deadline = Date.now() + (options.deadlineMs ?? DEFAULT_HEALTH_DEADLINE_MS);
4288
- const runtime = (0, import_node_path12.join)(options.dir, "runtime");
4490
+ const runtime = (0, import_node_path13.join)(options.dir, "runtime");
4289
4491
  const version = runtimeVersion(runtime);
4290
4492
  if (version !== options.expectedVersion) {
4291
4493
  throw new OperationsError(
@@ -4326,7 +4528,7 @@ async function verifyRunningInstallation(options) {
4326
4528
  }
4327
4529
  }
4328
4530
  const path2 = databasePath(options.dir);
4329
- if (!(0, import_node_fs11.existsSync)(path2)) {
4531
+ if (!(0, import_node_fs12.existsSync)(path2)) {
4330
4532
  if (status.active) {
4331
4533
  throw new OperationsError("database-missing", `hub database is missing after activation: ${path2}`);
4332
4534
  }
@@ -4366,8 +4568,8 @@ async function verifyRunningInstallation(options) {
4366
4568
  let problem = "collector has not sampled";
4367
4569
  while (Date.now() < deadline) {
4368
4570
  try {
4369
- const marker = JSON.parse(readPrivate((0, import_node_path12.join)(options.dir, "run", "collector-health.json")));
4370
- const owner = JSON.parse(readPrivate((0, import_node_path12.join)(options.dir, "collector", "collector-runtime.lock")));
4571
+ const marker = JSON.parse(readPrivate((0, import_node_path13.join)(options.dir, "run", "collector-health.json")));
4572
+ const owner = JSON.parse(readPrivate((0, import_node_path13.join)(options.dir, "collector", "collector-runtime.lock")));
4371
4573
  if (marker.version !== options.expectedVersion) throw new Error("collector version does not match the activated release");
4372
4574
  if (marker.pid !== owner.pid || !Number.isSafeInteger(marker.pid)) throw new Error("collector readiness belongs to another process");
4373
4575
  process.kill(marker.pid, 0);
@@ -4385,7 +4587,7 @@ async function verifyRunningInstallation(options) {
4385
4587
  return { version, health, database };
4386
4588
  }
4387
4589
  async function recoverActivation(options) {
4388
- const runtime = (0, import_node_path12.join)(options.dir, "runtime");
4590
+ const runtime = (0, import_node_path13.join)(options.dir, "runtime");
4389
4591
  const messages = [];
4390
4592
  let releaseLocks = null;
4391
4593
  try {
@@ -4394,12 +4596,16 @@ async function recoverActivation(options) {
4394
4596
  if (status.active) options.deps.service.stop(options.dir, component);
4395
4597
  }
4396
4598
  assertComponentsStopped(options.dir, options.deps, COMPONENT_LIST);
4397
- if ((0, import_node_fs11.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
4599
+ if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
4398
4600
  releaseLocks = acquireInstallLocks(options.dir, options.deps.acquireLease);
4601
+ messages.push(...undoMachineDataCleanup(machineDataPaths(options.dir), options.machineData?.stagedQueues ?? null));
4602
+ if (options.machineData?.report.warning) {
4603
+ messages.push(`machine-data cleanup was incomplete: ${options.machineData.report.warning}`);
4604
+ }
4399
4605
  if (options.activated) {
4400
4606
  try {
4401
- if ((0, import_node_fs11.existsSync)(runtime)) options.deps.swap(options.dir);
4402
- const restoredVersion = runtimeVersion((0, import_node_path12.join)(options.dir, "runtime"));
4607
+ if ((0, import_node_fs12.existsSync)(runtime)) options.deps.swap(options.dir);
4608
+ const restoredVersion = runtimeVersion((0, import_node_path13.join)(options.dir, "runtime"));
4403
4609
  if (restoredVersion !== options.previousVersion) {
4404
4610
  throw new Error(`restored runtime reports ${restoredVersion}, expected ${options.previousVersion}`);
4405
4611
  }
@@ -4410,10 +4616,11 @@ async function recoverActivation(options) {
4410
4616
  }
4411
4617
  }
4412
4618
  const path2 = databasePath(options.dir);
4413
- if (options.backupPath !== null && (0, import_node_fs11.existsSync)(options.backupPath) && (0, import_node_fs11.existsSync)(path2)) {
4619
+ const transitionClearedHistory = options.machineData?.databaseCleared === true;
4620
+ if (options.backupPath !== null && (0, import_node_fs12.existsSync)(options.backupPath) && (0, import_node_fs12.existsSync)(path2)) {
4414
4621
  try {
4415
- const old = options.deps.inspectRuntime((0, import_node_path12.join)(options.dir, "runtime"), path2);
4416
- if (!old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
4622
+ const old = options.deps.inspectRuntime((0, import_node_path13.join)(options.dir, "runtime"), path2);
4623
+ if (transitionClearedHistory || !old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
4417
4624
  const restored = await options.deps.restore({
4418
4625
  input: options.backupPath,
4419
4626
  database: path2,
@@ -4430,16 +4637,16 @@ async function recoverActivation(options) {
4430
4637
  messages.push(`database recovery failed: ${errorMessage(error2)}; pre-upgrade copy is ${options.backupPath}`);
4431
4638
  return messages.join("; ");
4432
4639
  }
4433
- } else if (options.backupPath === null && (0, import_node_fs11.existsSync)(path2)) {
4640
+ } else if (options.backupPath === null && (0, import_node_fs12.existsSync)(path2)) {
4434
4641
  try {
4435
- const old = options.deps.inspectRuntime((0, import_node_path12.join)(options.dir, "runtime"), path2);
4642
+ const old = options.deps.inspectRuntime((0, import_node_path13.join)(options.dir, "runtime"), path2);
4436
4643
  if (!old.integrityOk || old.newerSchema || old.ledgerProblem !== null) {
4437
- const backups = (0, import_node_path12.join)(options.dir, "backups");
4644
+ const backups = (0, import_node_path13.join)(options.dir, "backups");
4438
4645
  ensurePrivateDir(backups);
4439
- const preserved = (0, import_node_path12.join)(backups, `failed-activation-${timestampSlug(options.deps.now())}.sqlite`);
4440
- (0, import_node_fs11.renameSync)(path2, preserved);
4646
+ const preserved = (0, import_node_path13.join)(backups, `failed-activation-${timestampSlug(options.deps.now())}.sqlite`);
4647
+ (0, import_node_fs12.renameSync)(path2, preserved);
4441
4648
  for (const sidecar of [`${path2}-wal`, `${path2}-shm`]) {
4442
- if ((0, import_node_fs11.existsSync)(sidecar)) (0, import_node_fs11.renameSync)(sidecar, `${preserved}${sidecar.slice(path2.length)}`);
4649
+ if ((0, import_node_fs12.existsSync)(sidecar)) (0, import_node_fs12.renameSync)(sidecar, `${preserved}${sidecar.slice(path2.length)}`);
4443
4650
  }
4444
4651
  messages.push(`preserved the failed activation database at ${preserved}; the previous runtime will create a fresh database`);
4445
4652
  } else {
@@ -4483,8 +4690,8 @@ async function upgradeInstallation(options, injected = {}) {
4483
4690
  const deps = dependencies(injected);
4484
4691
  const config = readSetup(options.dir);
4485
4692
  if (!config) throw new OperationsError("not-installed", "No installation found. Run rigscope install first.");
4486
- const runtime = (0, import_node_path12.join)(options.dir, "runtime");
4487
- if (!(0, import_node_fs11.existsSync)(runtime)) {
4693
+ const runtime = (0, import_node_path13.join)(options.dir, "runtime");
4694
+ if (!(0, import_node_fs12.existsSync)(runtime)) {
4488
4695
  throw new OperationsError("not-installed", "Install a managed runtime before upgrading.");
4489
4696
  }
4490
4697
  const currentVersion = runtimeVersion(runtime);
@@ -4497,7 +4704,7 @@ async function upgradeInstallation(options, injected = {}) {
4497
4704
  expectedVersion = runtimeVersion(stage);
4498
4705
  assertRuntimeArtifacts(stage, "staged runtime");
4499
4706
  const path2 = databasePath(options.dir);
4500
- if ((0, import_node_fs11.existsSync)(path2)) {
4707
+ if ((0, import_node_fs12.existsSync)(path2)) {
4501
4708
  const staged = deps.inspectRuntime(stage, path2);
4502
4709
  if (!staged.integrityOk) {
4503
4710
  throw new OperationsError("database-integrity", `database integrity check failed before upgrade: ${path2}`);
@@ -4514,26 +4721,27 @@ async function upgradeInstallation(options, injected = {}) {
4514
4721
  expectedSchema = staged.supportedSchemaVersion;
4515
4722
  }
4516
4723
  } catch (error2) {
4517
- (0, import_node_fs11.rmSync)(stage, { recursive: true, force: true });
4724
+ (0, import_node_fs12.rmSync)(stage, { recursive: true, force: true });
4518
4725
  throw error2;
4519
4726
  }
4520
4727
  const snapshot = snapshotComponents(options.dir, deps);
4521
4728
  const running = snapshot.running;
4522
4729
  let releaseLocks = null;
4523
- const releaseOperation = deps.acquireLease((0, import_node_path12.join)(options.dir, "run", "operation.lock"));
4730
+ const releaseOperation = deps.acquireLease((0, import_node_path13.join)(options.dir, "run", "operation.lock"));
4524
4731
  let backupPath = null;
4525
4732
  let activated = false;
4733
+ let machineData = null;
4526
4734
  try {
4527
4735
  stopComponents(options.dir, deps, running);
4528
4736
  assertComponentsStopped(options.dir, deps, running);
4529
- if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs11.existsSync)(databasePath(options.dir))) {
4737
+ if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
4530
4738
  assertNoActiveHubLock(databasePath(options.dir));
4531
4739
  }
4532
4740
  releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
4533
- if ((0, import_node_fs11.existsSync)(databasePath(options.dir))) {
4534
- const backups = (0, import_node_path12.join)(options.dir, "backups");
4741
+ if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) {
4742
+ const backups = (0, import_node_path13.join)(options.dir, "backups");
4535
4743
  ensurePrivateDir(backups);
4536
- backupPath = (0, import_node_path12.join)(
4744
+ backupPath = (0, import_node_path13.join)(
4537
4745
  backups,
4538
4746
  `pre-upgrade-${currentVersion}-to-${expectedVersion}-${timestampSlug(deps.now())}.sqlite`
4539
4747
  );
@@ -4562,6 +4770,9 @@ async function upgradeInstallation(options, injected = {}) {
4562
4770
  }
4563
4771
  deps.activate(options.dir, stage);
4564
4772
  activated = true;
4773
+ machineData = performMachineDataCleanup(options.dir, machineDataPaths(options.dir), deps.now, {
4774
+ clear: deps.clearHistory
4775
+ });
4565
4776
  releaseLocks();
4566
4777
  releaseLocks = null;
4567
4778
  for (const component of running) deps.service.start(options.dir, component);
@@ -4577,7 +4788,7 @@ async function upgradeInstallation(options, injected = {}) {
4577
4788
  });
4578
4789
  restoreStartup(options.dir, deps, snapshot.enabled, false);
4579
4790
  const now = new Date(deps.now()).toISOString();
4580
- if (backupPath !== null && (0, import_node_fs11.existsSync)(backupPath)) {
4791
+ if (backupPath !== null && (0, import_node_fs12.existsSync)(backupPath)) {
4581
4792
  const info = deps.inspect(backupPath);
4582
4793
  const record = {
4583
4794
  path: backupPath,
@@ -4601,13 +4812,15 @@ async function upgradeInstallation(options, injected = {}) {
4601
4812
  activatedAt: now
4602
4813
  }
4603
4814
  });
4815
+ completeMachineDataCleanup(options.dir, machineData, expectedVersion);
4604
4816
  return {
4605
4817
  version: expectedVersion,
4606
4818
  previousVersion: currentVersion,
4607
4819
  backupPath,
4608
4820
  schemaVersion: verification.database?.schemaVersion ?? expectedSchema,
4609
4821
  serviceRestarted: running.length > 0,
4610
- verification
4822
+ verification,
4823
+ machineHistory: machineData.report
4611
4824
  };
4612
4825
  } catch (error2) {
4613
4826
  releaseLocks?.();
@@ -4617,6 +4830,7 @@ async function upgradeInstallation(options, injected = {}) {
4617
4830
  config,
4618
4831
  previousVersion: currentVersion,
4619
4832
  backupPath,
4833
+ machineData,
4620
4834
  running,
4621
4835
  startup: snapshot.enabled,
4622
4836
  activated,
@@ -4630,13 +4844,13 @@ async function upgradeInstallation(options, injected = {}) {
4630
4844
  } finally {
4631
4845
  releaseLocks?.();
4632
4846
  releaseOperation();
4633
- if ((0, import_node_fs11.existsSync)(stage)) (0, import_node_fs11.rmSync)(stage, { recursive: true, force: true });
4847
+ if ((0, import_node_fs12.existsSync)(stage)) (0, import_node_fs12.rmSync)(stage, { recursive: true, force: true });
4634
4848
  }
4635
4849
  }
4636
4850
  function rollbackBackup(options) {
4637
4851
  if (options.explicitBackup !== void 0) {
4638
4852
  const path2 = options.explicitBackup;
4639
- if (!(0, import_node_fs11.existsSync)(path2)) {
4853
+ if (!(0, import_node_fs12.existsSync)(path2)) {
4640
4854
  throw new OperationsError("backup-missing", `rollback backup does not exist: ${path2}`);
4641
4855
  }
4642
4856
  const info2 = options.deps.inspect(path2);
@@ -4655,7 +4869,7 @@ function rollbackBackup(options) {
4655
4869
  `database schema ${options.previousSupport.schemaVersion} is newer than previous runtime ${options.previousVersion} (schema ${options.previousSupport.supportedSchemaVersion}); no paired pre-upgrade backup is recorded for ${options.currentVersion}. Re-run with --backup PATH naming a copy that matches schema ${options.previousSupport.supportedSchemaVersion} or older`
4656
4870
  );
4657
4871
  }
4658
- if (!(0, import_node_fs11.existsSync)(recorded.path)) {
4872
+ if (!(0, import_node_fs12.existsSync)(recorded.path)) {
4659
4873
  throw new OperationsError(
4660
4874
  "backup-missing",
4661
4875
  `paired pre-upgrade backup for ${options.currentVersion} is missing: ${recorded.path}`
@@ -4677,10 +4891,10 @@ async function rollbackInstallation(options, injected = {}) {
4677
4891
  const deps = dependencies(injected);
4678
4892
  const config = readSetup(options.dir);
4679
4893
  if (!config) throw new OperationsError("not-installed", "No installation found. Run rigscope install first.");
4680
- const runtime = (0, import_node_path12.join)(options.dir, "runtime");
4681
- const previousRuntime = (0, import_node_path12.join)(options.dir, "runtime-previous");
4682
- if (!(0, import_node_fs11.existsSync)(runtime)) throw new OperationsError("not-installed", "No active runtime is installed.");
4683
- if (!(0, import_node_fs11.existsSync)(previousRuntime)) {
4894
+ const runtime = (0, import_node_path13.join)(options.dir, "runtime");
4895
+ const previousRuntime = (0, import_node_path13.join)(options.dir, "runtime-previous");
4896
+ if (!(0, import_node_fs12.existsSync)(runtime)) throw new OperationsError("not-installed", "No active runtime is installed.");
4897
+ if (!(0, import_node_fs12.existsSync)(previousRuntime)) {
4684
4898
  throw new OperationsError("no-previous-release", "No previous runtime is available for rollback.");
4685
4899
  }
4686
4900
  const currentVersion = runtimeVersion(runtime);
@@ -4691,19 +4905,19 @@ async function rollbackInstallation(options, injected = {}) {
4691
4905
  const snapshot = snapshotComponents(options.dir, deps);
4692
4906
  const running = snapshot.running;
4693
4907
  let releaseLocks = null;
4694
- const releaseOperation = deps.acquireLease((0, import_node_path12.join)(options.dir, "run", "operation.lock"));
4908
+ const releaseOperation = deps.acquireLease((0, import_node_path13.join)(options.dir, "run", "operation.lock"));
4695
4909
  let restoredBackup = null;
4696
4910
  let preRestoreBackup = null;
4697
4911
  let swapped = false;
4698
4912
  try {
4699
4913
  stopComponents(options.dir, deps, running);
4700
4914
  assertComponentsStopped(options.dir, deps, running);
4701
- if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs11.existsSync)(databasePath(options.dir))) {
4915
+ if (running.includes("hub") || componentEnabled(config, "hub") || (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
4702
4916
  assertNoActiveHubLock(databasePath(options.dir));
4703
4917
  }
4704
4918
  releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
4705
4919
  const path2 = databasePath(options.dir);
4706
- if ((0, import_node_fs11.existsSync)(path2)) {
4920
+ if ((0, import_node_fs12.existsSync)(path2)) {
4707
4921
  const previousSupport = deps.inspectRuntime(previousRuntime, path2);
4708
4922
  if (!previousSupport.integrityOk || previousSupport.newerSchema || previousSupport.ledgerProblem !== null) {
4709
4923
  const backup3 = rollbackBackup({
@@ -4774,7 +4988,7 @@ async function rollbackInstallation(options, injected = {}) {
4774
4988
  if (status.active) deps.service.stop(options.dir, component);
4775
4989
  }
4776
4990
  assertComponentsStopped(options.dir, deps, COMPONENT_LIST);
4777
- if ((0, import_node_fs11.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
4991
+ if ((0, import_node_fs12.existsSync)(databasePath(options.dir))) assertNoActiveHubLock(databasePath(options.dir));
4778
4992
  releaseLocks = acquireInstallLocks(options.dir, deps.acquireLease);
4779
4993
  } catch (stopError) {
4780
4994
  throw new OperationsError("rollback-failed", `rollback failed: ${errorMessage(error2)}. Recovery refused while runtime ownership is uncertain: ${errorMessage(stopError)}`, { cause: error2 });
@@ -4788,7 +5002,7 @@ async function rollbackInstallation(options, injected = {}) {
4788
5002
  safeToRestart = false;
4789
5003
  }
4790
5004
  }
4791
- if (preRestoreBackup !== null && (0, import_node_fs11.existsSync)(preRestoreBackup)) {
5005
+ if (preRestoreBackup !== null && (0, import_node_fs12.existsSync)(preRestoreBackup)) {
4792
5006
  try {
4793
5007
  await deps.restore({
4794
5008
  input: preRestoreBackup,
@@ -4803,7 +5017,7 @@ async function rollbackInstallation(options, injected = {}) {
4803
5017
  safeToRestart = false;
4804
5018
  }
4805
5019
  }
4806
- if (safeToRestart && running.includes("hub") && (0, import_node_fs11.existsSync)(databasePath(options.dir))) {
5020
+ if (safeToRestart && running.includes("hub") && (0, import_node_fs12.existsSync)(databasePath(options.dir))) {
4807
5021
  try {
4808
5022
  const info = deps.inspectRuntime(runtime, databasePath(options.dir));
4809
5023
  if (!info.integrityOk || info.newerSchema || info.ledgerProblem !== null) throw new Error("runtime/database compatibility is not established");
@@ -4850,17 +5064,17 @@ async function rollbackInstallation(options, injected = {}) {
4850
5064
 
4851
5065
  // src/cli/lifecycle.ts
4852
5066
  function collectorEnrolled(dir) {
4853
- const path2 = (0, import_node_path13.join)(dir, "collector", "state.json");
4854
- if (!(0, import_node_fs12.existsSync)(path2)) return false;
5067
+ const path2 = (0, import_node_path14.join)(dir, "collector", "state.json");
5068
+ if (!(0, import_node_fs13.existsSync)(path2)) return false;
4855
5069
  const state = JSON.parse(readPrivate(path2));
4856
5070
  return Array.isArray(state.destinations) && state.destinations.length > 0;
4857
5071
  }
4858
5072
  var AWAITING_CONNECTION = "Collector is awaiting connection. Run rigscope connect https://your-hub first.";
4859
5073
  function assertNoCompetingRuntime(dir, component) {
4860
5074
  const locks = [
4861
- (0, import_node_path13.join)(dir, "run", component === "hub" ? "hub.lock" : "collector.lock"),
4862
- (0, import_node_path13.join)(dir, "run", "rigscope.lock"),
4863
- ...component === "collector" ? [(0, import_node_path13.join)(dir, "collector", "collector-runtime.lock")] : []
5075
+ (0, import_node_path14.join)(dir, "run", component === "hub" ? "hub.lock" : "collector.lock"),
5076
+ (0, import_node_path14.join)(dir, "run", "rigscope.lock"),
5077
+ ...component === "collector" ? [(0, import_node_path14.join)(dir, "collector", "collector-runtime.lock")] : []
4864
5078
  ];
4865
5079
  const releases = [];
4866
5080
  try {
@@ -4879,11 +5093,11 @@ function assertNoCompetingRuntime(dir, component) {
4879
5093
  async function startInstallation(dir, component, injected = {}) {
4880
5094
  const config = readSetup(dir);
4881
5095
  if (!config) throw new Error("No background service installed. Run rigscope install first.");
4882
- if (!(0, import_node_fs12.existsSync)((0, import_node_path13.join)(dir, "runtime"))) throw new Error("No background service installed. Run rigscope install first.");
5096
+ if (!(0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, "runtime"))) throw new Error("No background service installed. Run rigscope install first.");
4883
5097
  const selected = component ? [component] : enabledComponents(config);
4884
5098
  if (selected.length === 0) throw new Error("No enabled components. Run rigscope enable hub or rigscope enable collector.");
4885
5099
  for (const target of selected) {
4886
- if (!(0, import_node_fs12.existsSync)(unitPath(dir, target))) throw new Error("No background service installed. Run rigscope install first.");
5100
+ if (!(0, import_node_fs13.existsSync)(unitPath(dir, target))) throw new Error("No background service installed. Run rigscope install first.");
4887
5101
  }
4888
5102
  const status = injected.status ?? serviceStatus;
4889
5103
  const start = injected.start ?? systemctl;
@@ -4911,7 +5125,7 @@ async function startInstallation(dir, component, injected = {}) {
4911
5125
  await (injected.verify ?? verifyRunningInstallation)({
4912
5126
  dir,
4913
5127
  config,
4914
- expectedVersion: runtimeVersion((0, import_node_path13.join)(dir, "runtime")),
5128
+ expectedVersion: runtimeVersion((0, import_node_path14.join)(dir, "runtime")),
4915
5129
  components: started,
4916
5130
  requireActive: started
4917
5131
  });
@@ -4995,11 +5209,11 @@ function printHelp(message, options = {}) {
4995
5209
 
4996
5210
  // src/cli/mutation.ts
4997
5211
  async function resumeComponent(dir, component) {
4998
- if ((0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, "runtime"))) return startInstallation(dir, component);
4999
- const run = (0, import_node_path14.join)(dir, "run");
5000
- (0, import_node_fs13.mkdirSync)(run, { recursive: true, mode: 448 });
5001
- const log = (0, import_node_path14.join)(run, `${component}.log`);
5002
- const fd = (0, import_node_fs13.openSync)(log, "a", 384);
5212
+ if ((0, import_node_fs14.existsSync)((0, import_node_path15.join)(dir, "runtime"))) return startInstallation(dir, component);
5213
+ const run = (0, import_node_path15.join)(dir, "run");
5214
+ (0, import_node_fs14.mkdirSync)(run, { recursive: true, mode: 448 });
5215
+ const log = (0, import_node_path15.join)(run, `${component}.log`);
5216
+ const fd = (0, import_node_fs14.openSync)(log, "a", 384);
5003
5217
  let child;
5004
5218
  try {
5005
5219
  child = (0, import_node_child_process3.spawn)(process.execPath, [process.argv[1], "run", component, "--state-dir", dir], {
@@ -5008,7 +5222,7 @@ async function resumeComponent(dir, component) {
5008
5222
  env: process.env
5009
5223
  });
5010
5224
  } finally {
5011
- (0, import_node_fs13.closeSync)(fd);
5225
+ (0, import_node_fs14.closeSync)(fd);
5012
5226
  }
5013
5227
  let failure;
5014
5228
  child.on("error", (error2) => {
@@ -5019,7 +5233,7 @@ async function resumeComponent(dir, component) {
5019
5233
  while (Date.now() < deadline) {
5020
5234
  if (failure || child.exitCode !== null || child.signalCode !== null) break;
5021
5235
  try {
5022
- const owner = JSON.parse((0, import_node_fs13.readFileSync)((0, import_node_path14.join)(run, `${component}.lock`), "utf8"));
5236
+ const owner = JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path15.join)(run, `${component}.lock`), "utf8"));
5023
5237
  if (owner.pid === child.pid) return "started";
5024
5238
  } catch {
5025
5239
  }
@@ -5075,12 +5289,20 @@ async function prepareMutation(dir, selected, options, deps = {}) {
5075
5289
 
5076
5290
  // src/cli/runtime.ts
5077
5291
  var import_node_child_process4 = require("node:child_process");
5078
- var import_node_path15 = require("node:path");
5292
+ var import_node_path16 = require("node:path");
5293
+ function collectorQueueModeEnvironment(env) {
5294
+ const raw = env["COLLECTOR_QUEUE_MODE"]?.trim();
5295
+ if (raw === void 0 || raw === "") return {};
5296
+ const issues = [];
5297
+ const queueMode = parseQueueMode(env, issues);
5298
+ if (issues.length > 0) throw new Error(issues.join("\n"));
5299
+ return { COLLECTOR_QUEUE_MODE: queueMode };
5300
+ }
5079
5301
  function componentLeasePath(dir, component) {
5080
- return (0, import_node_path15.join)(dir, "run", `${component}.lock`);
5302
+ return (0, import_node_path16.join)(dir, "run", `${component}.lock`);
5081
5303
  }
5082
5304
  function combinedLeasePath(dir) {
5083
- return (0, import_node_path15.join)(dir, "run", "rigscope.lock");
5305
+ return (0, import_node_path16.join)(dir, "run", "rigscope.lock");
5084
5306
  }
5085
5307
  function label(component) {
5086
5308
  return component === "hub" ? "Hub" : "Collector";
@@ -5097,6 +5319,7 @@ async function runInstallation(root, dir, component) {
5097
5319
  console.error("No components are enabled. Run rigscope enable hub or rigscope enable collector.");
5098
5320
  return 0;
5099
5321
  }
5322
+ const collectorEnvironment = selected.includes("collector") ? collectorQueueModeEnvironment(process.env) : {};
5100
5323
  if (selected.includes("collector") && !collectorHasDestinations(dir)) {
5101
5324
  console.log("Collector awaiting connection. Run rigscope connect https://your-hub.");
5102
5325
  const remaining = selected.filter((role) => role !== "collector");
@@ -5136,13 +5359,14 @@ async function runInstallation(root, dir, component) {
5136
5359
  process.on("SIGTERM", signal);
5137
5360
  process.on("SIGINT", signal);
5138
5361
  function launch(role) {
5139
- const child = (0, import_node_child_process4.spawn)(process.execPath, [(0, import_node_path15.join)(root, "dist", `${role}.cjs`)], { cwd: root, stdio: "inherit", env: {
5362
+ const child = (0, import_node_child_process4.spawn)(process.execPath, [(0, import_node_path16.join)(root, "dist", `${role}.cjs`)], { cwd: root, stdio: "inherit", env: {
5140
5363
  ...environment,
5141
5364
  NODE_ENV: "production",
5142
5365
  ...role === "hub" ? hubEnvironment(dir, config) : {
5143
5366
  COLLECTOR_MODE: "real",
5144
- COLLECTOR_STATE_FILE: (0, import_node_path15.join)(dir, "collector", "state.json"),
5145
- COLLECTOR_HEALTH_FILE: (0, import_node_path15.join)(dir, "run", "collector-health.json")
5367
+ COLLECTOR_STATE_FILE: (0, import_node_path16.join)(dir, "collector", "state.json"),
5368
+ COLLECTOR_HEALTH_FILE: (0, import_node_path16.join)(dir, "run", "collector-health.json"),
5369
+ ...collectorEnvironment
5146
5370
  }
5147
5371
  } });
5148
5372
  children.add(child);
@@ -5169,8 +5393,8 @@ async function runInstallation(root, dir, component) {
5169
5393
  }
5170
5394
 
5171
5395
  // src/cli/doctor.ts
5172
- var import_node_fs14 = require("node:fs");
5173
- var import_node_path16 = require("node:path");
5396
+ var import_node_fs15 = require("node:fs");
5397
+ var import_node_path17 = require("node:path");
5174
5398
  var DEFAULT_DEPENDENCIES = {
5175
5399
  serviceStatus,
5176
5400
  probeHealth,
@@ -5180,7 +5404,7 @@ var DEFAULT_DEPENDENCIES = {
5180
5404
  inspectDatabase,
5181
5405
  diskFree: (path2) => {
5182
5406
  try {
5183
- const stats = (0, import_node_fs14.statfsSync)(path2);
5407
+ const stats = (0, import_node_fs15.statfsSync)(path2);
5184
5408
  return { free: Number(stats.bavail) * Number(stats.bsize), total: Number(stats.blocks) * Number(stats.bsize) };
5185
5409
  } catch {
5186
5410
  return null;
@@ -5189,13 +5413,13 @@ var DEFAULT_DEPENDENCIES = {
5189
5413
  sensorReadable: (paths) => paths.filter((path2) => {
5190
5414
  let fd;
5191
5415
  try {
5192
- fd = (0, import_node_fs14.openSync)(path2, "r");
5193
- (0, import_node_fs14.readSync)(fd, Buffer.alloc(1), 0, 1, 0);
5416
+ fd = (0, import_node_fs15.openSync)(path2, "r");
5417
+ (0, import_node_fs15.readSync)(fd, Buffer.alloc(1), 0, 1, 0);
5194
5418
  return true;
5195
5419
  } catch {
5196
5420
  return false;
5197
5421
  } finally {
5198
- if (fd !== void 0) (0, import_node_fs14.closeSync)(fd);
5422
+ if (fd !== void 0) (0, import_node_fs15.closeSync)(fd);
5199
5423
  }
5200
5424
  })
5201
5425
  };
@@ -5257,10 +5481,10 @@ async function diagnoseInstallation(dir, injected = {}) {
5257
5481
  }
5258
5482
  for (const [id, label3, path2] of [
5259
5483
  ["state-dir", "State directory", dir],
5260
- ["config-mode", "Configuration permissions", (0, import_node_path16.join)(dir, "config.json")]
5484
+ ["config-mode", "Configuration permissions", (0, import_node_path17.join)(dir, "config.json")]
5261
5485
  ]) {
5262
5486
  try {
5263
- const stat = (0, import_node_fs14.lstatSync)(path2);
5487
+ const stat = (0, import_node_fs15.lstatSync)(path2);
5264
5488
  const privateEntry = id === "state-dir" ? stat.isDirectory() : stat.isFile();
5265
5489
  const privateMode = (stat.mode & 63) === 0;
5266
5490
  add({
@@ -5275,7 +5499,7 @@ async function diagnoseInstallation(dir, injected = {}) {
5275
5499
  }
5276
5500
  }
5277
5501
  let runtime = null;
5278
- if (!(0, import_node_fs14.existsSync)((0, import_node_path16.join)(dir, "runtime"))) {
5502
+ if (!(0, import_node_fs15.existsSync)((0, import_node_path17.join)(dir, "runtime"))) {
5279
5503
  add({
5280
5504
  id: "runtime",
5281
5505
  label: "Runtime",
@@ -5285,9 +5509,9 @@ async function diagnoseInstallation(dir, injected = {}) {
5285
5509
  });
5286
5510
  } else {
5287
5511
  try {
5288
- assertRuntimeArtifacts((0, import_node_path16.join)(dir, "runtime"), "runtime");
5289
- const version2 = runtimeVersion((0, import_node_path16.join)(dir, "runtime"));
5290
- runtime = (0, import_node_path16.join)(dir, "runtime");
5512
+ assertRuntimeArtifacts((0, import_node_path17.join)(dir, "runtime"), "runtime");
5513
+ const version2 = runtimeVersion((0, import_node_path17.join)(dir, "runtime"));
5514
+ runtime = (0, import_node_path17.join)(dir, "runtime");
5291
5515
  add({ id: "runtime", label: "Runtime", status: "ok", detail: `rigscope ${version2}` });
5292
5516
  } catch (error2) {
5293
5517
  add({
@@ -5299,9 +5523,9 @@ async function diagnoseInstallation(dir, injected = {}) {
5299
5523
  });
5300
5524
  }
5301
5525
  }
5302
- if ((0, import_node_fs14.existsSync)((0, import_node_path16.join)(dir, "runtime-previous"))) {
5526
+ if ((0, import_node_fs15.existsSync)((0, import_node_path17.join)(dir, "runtime-previous"))) {
5303
5527
  try {
5304
- add({ id: "previous-runtime", label: "Previous runtime", status: "ok", detail: `rigscope ${runtimeVersion((0, import_node_path16.join)(dir, "runtime-previous"))}` });
5528
+ add({ id: "previous-runtime", label: "Previous runtime", status: "ok", detail: `rigscope ${runtimeVersion((0, import_node_path17.join)(dir, "runtime-previous"))}` });
5305
5529
  } catch (error2) {
5306
5530
  add({ id: "previous-runtime", label: "Previous runtime", status: "warn", detail: errorText2(error2) });
5307
5531
  }
@@ -5363,7 +5587,7 @@ async function diagnoseInstallation(dir, injected = {}) {
5363
5587
  const collectorActive = services.collector.active;
5364
5588
  if (hubEnabled || hubActive) {
5365
5589
  const path2 = databasePath(dir);
5366
- if (!(0, import_node_fs14.existsSync)(path2)) {
5590
+ if (!(0, import_node_fs15.existsSync)(path2)) {
5367
5591
  add({
5368
5592
  id: "database",
5369
5593
  label: "Database",
@@ -5392,7 +5616,7 @@ async function diagnoseInstallation(dir, injected = {}) {
5392
5616
  });
5393
5617
  }
5394
5618
  }
5395
- const space = deps.diskFree((0, import_node_path16.join)(dir, "hub"));
5619
+ const space = deps.diskFree((0, import_node_path17.join)(dir, "hub"));
5396
5620
  if (space !== null) {
5397
5621
  const free = space.free;
5398
5622
  add({
@@ -5406,9 +5630,9 @@ async function diagnoseInstallation(dir, injected = {}) {
5406
5630
  }
5407
5631
  if (hubEnabled || hubActive) {
5408
5632
  if (config.origin) {
5409
- const socket = config.socket ?? (0, import_node_path16.join)(dir, "run", "hub.sock");
5633
+ const socket = config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock");
5410
5634
  try {
5411
- const stat = (0, import_node_fs14.lstatSync)(socket);
5635
+ const stat = (0, import_node_fs15.lstatSync)(socket);
5412
5636
  add({
5413
5637
  id: "socket",
5414
5638
  label: "Unix socket",
@@ -5450,7 +5674,7 @@ async function diagnoseInstallation(dir, injected = {}) {
5450
5674
  }
5451
5675
  if (hubActive) {
5452
5676
  try {
5453
- const target = healthTarget({ component: "hub", port: config.port, origin: config.origin, socket: config.socket ?? (0, import_node_path16.join)(dir, "run", "hub.sock") });
5677
+ const target = healthTarget({ component: "hub", port: config.port, origin: config.origin, socket: config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock") });
5454
5678
  const health = await deps.probeHealth(target, 3e3);
5455
5679
  const expected = runtime ? runtimeVersion(runtime) : null;
5456
5680
  const reported = typeof health.body?.version === "string" ? health.body.version : null;
@@ -5468,7 +5692,7 @@ async function diagnoseInstallation(dir, injected = {}) {
5468
5692
  }
5469
5693
  }
5470
5694
  if (collectorEnabled || collectorActive) {
5471
- const statePath = (0, import_node_path16.join)(dir, "collector", "state.json");
5695
+ const statePath = (0, import_node_path17.join)(dir, "collector", "state.json");
5472
5696
  try {
5473
5697
  const raw = readPrivate(statePath);
5474
5698
  const state = JSON.parse(raw);
@@ -5543,17 +5767,17 @@ async function diagnoseInstallation(dir, injected = {}) {
5543
5767
  function hubEnvironment2(dir, config) {
5544
5768
  return {
5545
5769
  ...!config.origin ? { HUB_HOST: "127.0.0.1", HUB_PORT: String(config.port) } : {},
5546
- HUB_STATE_FILE: (0, import_node_path16.join)(dir, "hub", "enrollment.json"),
5770
+ HUB_STATE_FILE: (0, import_node_path17.join)(dir, "hub", "enrollment.json"),
5547
5771
  HUB_DATABASE_PATH: databasePath(dir),
5548
5772
  HUB_BROWSER_USERS: JSON.stringify(config.users),
5549
5773
  HUB_COLLECTORS: JSON.stringify(config.collectors),
5550
5774
  ...config.maxCollectorConnections === void 0 ? {} : { HUB_MAX_COLLECTOR_CONNECTIONS: String(config.maxCollectorConnections) },
5551
- ...config.origin ? { HUB_PUBLIC_ORIGIN: config.origin, HUB_SOCKET_PATH: config.socket ?? (0, import_node_path16.join)(dir, "run", "hub.sock") } : {}
5775
+ ...config.origin ? { HUB_PUBLIC_ORIGIN: config.origin, HUB_SOCKET_PATH: config.socket ?? (0, import_node_path17.join)(dir, "run", "hub.sock") } : {}
5552
5776
  };
5553
5777
  }
5554
5778
  function collectorAwaiting(dir) {
5555
5779
  try {
5556
- const state = JSON.parse(readPrivate((0, import_node_path16.join)(dir, "collector", "state.json")));
5780
+ const state = JSON.parse(readPrivate((0, import_node_path17.join)(dir, "collector", "state.json")));
5557
5781
  return !Array.isArray(state.destinations) || state.destinations.length === 0;
5558
5782
  } catch (error2) {
5559
5783
  return error2.code === "ENOENT";
@@ -5565,13 +5789,13 @@ function powerCounterPaths() {
5565
5789
  if (depth > 3 || paths.length >= 64) return;
5566
5790
  let entries;
5567
5791
  try {
5568
- entries = (0, import_node_fs14.readdirSync)(directory, { withFileTypes: true });
5792
+ entries = (0, import_node_fs15.readdirSync)(directory, { withFileTypes: true });
5569
5793
  } catch {
5570
5794
  return;
5571
5795
  }
5572
5796
  for (const entry2 of entries) {
5573
5797
  if (paths.length >= 64) return;
5574
- const path2 = (0, import_node_path16.join)(directory, entry2.name);
5798
+ const path2 = (0, import_node_path17.join)(directory, entry2.name);
5575
5799
  if (entry2.name === "energy_uj") {
5576
5800
  paths.push(path2);
5577
5801
  continue;
@@ -5615,8 +5839,8 @@ function errorText2(error2) {
5615
5839
  }
5616
5840
 
5617
5841
  // src/operations/recovery.ts
5618
- var import_node_fs15 = require("node:fs");
5619
- var import_node_path17 = require("node:path");
5842
+ var import_node_fs16 = require("node:fs");
5843
+ var import_node_path18 = require("node:path");
5620
5844
  var import_node_sqlite3 = require("node:sqlite");
5621
5845
  var MAX_AUDIT_EVENTS = 1e3;
5622
5846
  var AUDIT_ACTOR = "local-recovery";
@@ -5631,13 +5855,13 @@ async function recoverAdminPassword(options) {
5631
5855
  if (typeof options.password !== "string" || options.password.length === 0 || options.password.length > MAX_BROWSER_PASSWORD_CHARS) {
5632
5856
  throw new OperationsError("invalid-password", `password must be 1..${MAX_BROWSER_PASSWORD_CHARS} characters`);
5633
5857
  }
5634
- if (!(0, import_node_fs15.existsSync)(database)) {
5858
+ if (!(0, import_node_fs16.existsSync)(database)) {
5635
5859
  throw new OperationsError("missing-database", `hub database does not exist: ${database}`);
5636
5860
  }
5637
5861
  assertPrivateRegularFile(database, "database");
5638
- const ownLock = (0, import_node_path17.resolve)(`${database}.hub.lock`);
5862
+ const ownLock = (0, import_node_path18.resolve)(`${database}.hub.lock`);
5639
5863
  const otherLock = findHubLock(database);
5640
- if (otherLock !== null && (0, import_node_path17.resolve)(otherLock) !== ownLock) {
5864
+ if (otherLock !== null && (0, import_node_path18.resolve)(otherLock) !== ownLock) {
5641
5865
  throw new OperationsError(
5642
5866
  "hub-active",
5643
5867
  `a hub lock exists at ${otherLock}; stop the hub and inspect that lock before recovery`
@@ -5735,10 +5959,10 @@ async function recoverAdminPassword(options) {
5735
5959
  }
5736
5960
 
5737
5961
  // src/cli/system.ts
5738
- var import_node_fs16 = require("node:fs");
5962
+ var import_node_fs17 = require("node:fs");
5739
5963
  var import_node_child_process5 = require("node:child_process");
5740
- var import_node_crypto11 = require("node:crypto");
5741
- var import_node_path18 = require("node:path");
5964
+ var import_node_crypto12 = require("node:crypto");
5965
+ var import_node_path19 = require("node:path");
5742
5966
  var import_node_sqlite4 = require("node:sqlite");
5743
5967
  var import_node_util = require("node:util");
5744
5968
  var SYSTEM_SCOPE = "system";
@@ -5848,24 +6072,24 @@ function createSystemHost(overrides = {}) {
5848
6072
  }
5849
6073
  function defaultSystemPaths(overrides = {}) {
5850
6074
  return {
5851
- prefix: (0, import_node_path18.resolve)(overrides.prefix ?? "/opt/rigscope"),
5852
- configDir: (0, import_node_path18.resolve)(overrides.configDir ?? "/etc/rigscope"),
5853
- stateDir: (0, import_node_path18.resolve)(overrides.stateDir ?? "/var/lib/rigscope"),
5854
- unitsDir: (0, import_node_path18.resolve)(overrides.unitsDir ?? "/etc/systemd/system"),
5855
- sysusersDir: (0, import_node_path18.resolve)(overrides.sysusersDir ?? "/etc/sysusers.d"),
5856
- udevRulesDir: (0, import_node_path18.resolve)(overrides.udevRulesDir ?? "/etc/udev/rules.d"),
5857
- powercapRoot: (0, import_node_path18.resolve)(overrides.powercapRoot ?? "/sys/class/powercap")
6075
+ prefix: (0, import_node_path19.resolve)(overrides.prefix ?? "/opt/rigscope"),
6076
+ configDir: (0, import_node_path19.resolve)(overrides.configDir ?? "/etc/rigscope"),
6077
+ stateDir: (0, import_node_path19.resolve)(overrides.stateDir ?? "/var/lib/rigscope"),
6078
+ unitsDir: (0, import_node_path19.resolve)(overrides.unitsDir ?? "/etc/systemd/system"),
6079
+ sysusersDir: (0, import_node_path19.resolve)(overrides.sysusersDir ?? "/etc/sysusers.d"),
6080
+ udevRulesDir: (0, import_node_path19.resolve)(overrides.udevRulesDir ?? "/etc/udev/rules.d"),
6081
+ powercapRoot: (0, import_node_path19.resolve)(overrides.powercapRoot ?? "/sys/class/powercap")
5858
6082
  };
5859
6083
  }
5860
6084
  function unitNamesForComponents(components) {
5861
6085
  return COMPONENTS3.filter((component) => componentSet(components)[component]).map(unitFor);
5862
6086
  }
5863
6087
  function isWithin(parent, candidate) {
5864
- const rel = (0, import_node_path18.relative)((0, import_node_path18.resolve)(parent), (0, import_node_path18.resolve)(candidate));
5865
- return rel === "" || rel !== ".." && !rel.startsWith(`..${import_node_path18.sep}`) && !(0, import_node_path18.isAbsolute)(rel);
6088
+ const rel = (0, import_node_path19.relative)((0, import_node_path19.resolve)(parent), (0, import_node_path19.resolve)(candidate));
6089
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${import_node_path19.sep}`) && !(0, import_node_path19.isAbsolute)(rel);
5866
6090
  }
5867
6091
  function ensureAbsolute(path2, label3) {
5868
- const absolute = (0, import_node_path18.resolve)(path2);
6092
+ const absolute = (0, import_node_path19.resolve)(path2);
5869
6093
  if (/[\0\r\n]/.test(absolute)) throw new SystemError("unsafe-path", `${label3} contains control characters`);
5870
6094
  if (absolute === "/") throw new SystemError("unsafe-path", `${label3} must not be the filesystem root`);
5871
6095
  for (const forbidden of ["/home", "/root", "/proc", "/sys", "/dev", "/boot"]) {
@@ -5879,7 +6103,7 @@ function validateSystemPaths(input = {}) {
5879
6103
  const paths = defaultSystemPaths(input);
5880
6104
  for (const [label3, value] of Object.entries(paths)) {
5881
6105
  if (label3 === "powercapRoot") {
5882
- if (!(0, import_node_path18.isAbsolute)(value) || /[\0\r\n]/.test(value) || (0, import_node_path18.resolve)(value) === "/") {
6106
+ if (!(0, import_node_path19.isAbsolute)(value) || /[\0\r\n]/.test(value) || (0, import_node_path19.resolve)(value) === "/") {
5883
6107
  throw new SystemError("unsafe-path", `powercap root is unsafe: ${value}`);
5884
6108
  }
5885
6109
  } else {
@@ -5935,18 +6159,18 @@ function runMaybe(host, command, args, options) {
5935
6159
  return host.run(command, args, options);
5936
6160
  }
5937
6161
  function sha256File2(path2) {
5938
- return (0, import_node_crypto11.createHash)("sha256").update((0, import_node_fs16.readFileSync)(path2)).digest("hex");
6162
+ return (0, import_node_crypto12.createHash)("sha256").update((0, import_node_fs17.readFileSync)(path2)).digest("hex");
5939
6163
  }
5940
6164
  function atomicWrite(path2, content, mode) {
5941
- (0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(path2), { recursive: true, mode: 493 });
5942
- const temporary = (0, import_node_path18.join)((0, import_node_path18.dirname)(path2), `.${(0, import_node_path18.basename)(path2)}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
6165
+ (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(path2), { recursive: true, mode: 493 });
6166
+ const temporary = (0, import_node_path19.join)((0, import_node_path19.dirname)(path2), `.${(0, import_node_path19.basename)(path2)}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
5943
6167
  try {
5944
- (0, import_node_fs16.writeFileSync)(temporary, content, { mode });
5945
- (0, import_node_fs16.chmodSync)(temporary, mode);
5946
- (0, import_node_fs16.renameSync)(temporary, path2);
6168
+ (0, import_node_fs17.writeFileSync)(temporary, content, { mode });
6169
+ (0, import_node_fs17.chmodSync)(temporary, mode);
6170
+ (0, import_node_fs17.renameSync)(temporary, path2);
5947
6171
  } catch (error2) {
5948
6172
  try {
5949
- (0, import_node_fs16.unlinkSync)(temporary);
6173
+ (0, import_node_fs17.unlinkSync)(temporary);
5950
6174
  } catch {
5951
6175
  }
5952
6176
  throw error2;
@@ -5955,12 +6179,12 @@ function atomicWrite(path2, content, mode) {
5955
6179
  function ensureDirectory(path2, mode, privateDirectory2 = false) {
5956
6180
  let stat;
5957
6181
  try {
5958
- stat = (0, import_node_fs16.lstatSync)(path2);
6182
+ stat = (0, import_node_fs17.lstatSync)(path2);
5959
6183
  } catch (error2) {
5960
6184
  if (error2.code !== "ENOENT") throw error2;
5961
- (0, import_node_fs16.mkdirSync)(path2, { recursive: true, mode });
5962
- (0, import_node_fs16.chmodSync)(path2, mode);
5963
- stat = (0, import_node_fs16.lstatSync)(path2);
6185
+ (0, import_node_fs17.mkdirSync)(path2, { recursive: true, mode });
6186
+ (0, import_node_fs17.chmodSync)(path2, mode);
6187
+ stat = (0, import_node_fs17.lstatSync)(path2);
5964
6188
  }
5965
6189
  if (!stat.isDirectory() || stat.isSymbolicLink()) {
5966
6190
  throw new SystemError("unsafe-path", `${path2} must be a real directory`);
@@ -5975,8 +6199,8 @@ function isDefaultSystemLayout(paths) {
5975
6199
  }
5976
6200
  function assertManagedPathSafety(paths, enforceRoot) {
5977
6201
  for (const path2 of [paths.prefix, paths.configDir, paths.stateDir, paths.unitsDir, paths.sysusersDir, paths.udevRulesDir]) {
5978
- if (!(0, import_node_fs16.existsSync)(path2)) continue;
5979
- const stat = (0, import_node_fs16.lstatSync)(path2);
6202
+ if (!(0, import_node_fs17.existsSync)(path2)) continue;
6203
+ const stat = (0, import_node_fs17.lstatSync)(path2);
5980
6204
  if (!stat.isDirectory() || stat.isSymbolicLink()) {
5981
6205
  throw new SystemError("unsafe-path", `${path2} must be a real directory`);
5982
6206
  }
@@ -5989,8 +6213,8 @@ function assertManagedPathSafety(paths, enforceRoot) {
5989
6213
  }
5990
6214
  }
5991
6215
  function writeManagedFile(path2, content, mode, replace) {
5992
- if ((0, import_node_fs16.existsSync)(path2)) {
5993
- const stat = (0, import_node_fs16.lstatSync)(path2);
6216
+ if ((0, import_node_fs17.existsSync)(path2)) {
6217
+ const stat = (0, import_node_fs17.lstatSync)(path2);
5994
6218
  if (!stat.isFile() || stat.isSymbolicLink()) {
5995
6219
  throw new SystemError("unsafe-path", `${path2} must be a regular file, not a symlink`);
5996
6220
  }
@@ -6029,7 +6253,7 @@ function parseEnvValue(value) {
6029
6253
  function readEnvDocument(path2) {
6030
6254
  let raw;
6031
6255
  try {
6032
- raw = (0, import_node_fs16.readFileSync)(path2, "utf8");
6256
+ raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
6033
6257
  } catch (error2) {
6034
6258
  if (error2.code === "ENOENT") return null;
6035
6259
  throw error2;
@@ -6076,43 +6300,43 @@ function connectDestinationUrl(value) {
6076
6300
  return url.href;
6077
6301
  }
6078
6302
  function hubDatabasePath(paths) {
6079
- return (0, import_node_path18.join)(paths.stateDir, "hub", "telemetry.sqlite");
6303
+ return (0, import_node_path19.join)(paths.stateDir, "hub", "telemetry.sqlite");
6080
6304
  }
6081
6305
  function hubEnrollmentPath(paths) {
6082
- return (0, import_node_path18.join)(paths.stateDir, "hub", "enrollment.json");
6306
+ return (0, import_node_path19.join)(paths.stateDir, "hub", "enrollment.json");
6083
6307
  }
6084
6308
  function hubSocketPath(paths) {
6085
- return (0, import_node_path18.join)(paths.stateDir, "hub", "run", "hub.sock");
6309
+ return (0, import_node_path19.join)(paths.stateDir, "hub", "run", "hub.sock");
6086
6310
  }
6087
6311
  function collectorStatePath2(paths) {
6088
- return (0, import_node_path18.join)(paths.stateDir, "collector", "state.json");
6312
+ return (0, import_node_path19.join)(paths.stateDir, "collector", "state.json");
6089
6313
  }
6090
6314
  function hubEnvPath(paths) {
6091
- return (0, import_node_path18.join)(paths.configDir, "hub.env");
6315
+ return (0, import_node_path19.join)(paths.configDir, "hub.env");
6092
6316
  }
6093
6317
  function collectorEnvPath(paths) {
6094
- return (0, import_node_path18.join)(paths.configDir, "collector.env");
6318
+ return (0, import_node_path19.join)(paths.configDir, "collector.env");
6095
6319
  }
6096
6320
  function sysusersPath(paths) {
6097
- return (0, import_node_path18.join)(paths.sysusersDir, SYSUSERS_NAME);
6321
+ return (0, import_node_path19.join)(paths.sysusersDir, SYSUSERS_NAME);
6098
6322
  }
6099
6323
  function powerSysusersPath(paths) {
6100
- return (0, import_node_path18.join)(paths.sysusersDir, POWER_SYSUSERS_NAME);
6324
+ return (0, import_node_path19.join)(paths.sysusersDir, POWER_SYSUSERS_NAME);
6101
6325
  }
6102
6326
  function raplRulePath(paths) {
6103
- return (0, import_node_path18.join)(paths.udevRulesDir, RAPL_RULE_NAME);
6327
+ return (0, import_node_path19.join)(paths.udevRulesDir, RAPL_RULE_NAME);
6104
6328
  }
6105
6329
  function stateFilePath(paths) {
6106
- return (0, import_node_path18.join)(paths.stateDir, STATE_FILE_NAME);
6330
+ return (0, import_node_path19.join)(paths.stateDir, STATE_FILE_NAME);
6107
6331
  }
6108
6332
  function readCollectorIdentity(path2) {
6109
- if (!(0, import_node_fs16.existsSync)(path2)) return null;
6110
- const stat = (0, import_node_fs16.lstatSync)(path2);
6333
+ if (!(0, import_node_fs17.existsSync)(path2)) return null;
6334
+ const stat = (0, import_node_fs17.lstatSync)(path2);
6111
6335
  if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("unsafe-path", `${path2} must be a regular file`);
6112
6336
  if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `${path2} must be private (0600)`);
6113
6337
  let raw;
6114
6338
  try {
6115
- raw = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
6339
+ raw = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
6116
6340
  } catch {
6117
6341
  throw new SystemError("invalid-file", `${path2} is not valid JSON`);
6118
6342
  }
@@ -6146,7 +6370,7 @@ function readCollectorIdentity(path2) {
6146
6370
  return { collectorId: record.collectorId, destinations };
6147
6371
  }
6148
6372
  function writeCollectorIdentity(path2, identity) {
6149
- ensureDirectory((0, import_node_path18.dirname)(path2), 448, true);
6373
+ ensureDirectory((0, import_node_path19.dirname)(path2), 448, true);
6150
6374
  atomicWrite(path2, `${JSON.stringify(identity)}
6151
6375
  `, 384);
6152
6376
  }
@@ -6186,7 +6410,7 @@ function ensureHubOwner(paths) {
6186
6410
  if (!Array.isArray(parsed)) throw new SystemError("invalid-config", "HUB_BROWSER_USERS must be a JSON array");
6187
6411
  if (parsed.length > 0) return void 0;
6188
6412
  }
6189
- const password = (0, import_node_crypto11.randomBytes)(18).toString("base64url");
6413
+ const password = (0, import_node_crypto12.randomBytes)(18).toString("base64url");
6190
6414
  const users = [{ username: "owner", passwordHash: hashPassword(password), machineIds: "*", admin: true }];
6191
6415
  writeEnvValue(hubEnvPath(paths), "HUB_BROWSER_USERS", JSON.stringify(users));
6192
6416
  return password;
@@ -6237,7 +6461,7 @@ function updateHubCollectorRegistry(paths, identity) {
6237
6461
  }
6238
6462
  function registerCollectorInHubDatabase(paths, identity, host) {
6239
6463
  const database = hubDatabasePath(paths);
6240
- if (!(0, import_node_fs16.existsSync)(database)) return { inserted: false };
6464
+ if (!(0, import_node_fs17.existsSync)(database)) return { inserted: false };
6241
6465
  const db = new import_node_sqlite4.DatabaseSync(database, { timeout: 5e3 });
6242
6466
  try {
6243
6467
  const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='collector_registry'").get();
@@ -6252,7 +6476,7 @@ function registerCollectorInHubDatabase(paths, identity, host) {
6252
6476
  }
6253
6477
  function findCollectorInHubDatabase(paths, collectorId) {
6254
6478
  const database = hubDatabasePath(paths);
6255
- if (!(0, import_node_fs16.existsSync)(database)) return null;
6479
+ if (!(0, import_node_fs17.existsSync)(database)) return null;
6256
6480
  const db = new import_node_sqlite4.DatabaseSync(database, { readOnly: true, timeout: 5e3 });
6257
6481
  try {
6258
6482
  const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='collector_registry'").get();
@@ -6265,9 +6489,9 @@ function findCollectorInHubDatabase(paths, collectorId) {
6265
6489
  }
6266
6490
  function createLocalEnrollmentGrant(paths, host) {
6267
6491
  const database = hubDatabasePath(paths);
6268
- if (!(0, import_node_fs16.existsSync)(database)) throw new SystemError("hub-unavailable", "the hub database does not exist yet");
6269
- const token = (0, import_node_crypto11.randomBytes)(32).toString("base64url");
6270
- const tokenHash = (0, import_node_crypto11.createHash)("sha256").update(token).digest("hex");
6492
+ if (!(0, import_node_fs17.existsSync)(database)) throw new SystemError("hub-unavailable", "the hub database does not exist yet");
6493
+ const token = (0, import_node_crypto12.randomBytes)(32).toString("base64url");
6494
+ const tokenHash = (0, import_node_crypto12.createHash)("sha256").update(token).digest("hex");
6271
6495
  const expiresAt = host.now() + 10 * 60 * 1e3;
6272
6496
  const db = new import_node_sqlite4.DatabaseSync(database, { timeout: 5e3 });
6273
6497
  try {
@@ -6319,7 +6543,7 @@ async function pairCollectorWithHub(options) {
6319
6543
  note: "the local hub has no reachable loopback or HTTPS destination"
6320
6544
  };
6321
6545
  }
6322
- if (!(0, import_node_fs16.existsSync)((0, import_node_path18.join)(paths.unitsDir, UNIT_NAMES.hub))) {
6546
+ if (!(0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, UNIT_NAMES.hub))) {
6323
6547
  return { paired: false, awaiting: true, hubWasActive: false, note: "the local hub unit is not installed" };
6324
6548
  }
6325
6549
  const hubWasActive = systemdActive(host, UNIT_NAMES.hub);
@@ -6332,7 +6556,7 @@ async function pairCollectorWithHub(options) {
6332
6556
  destinations: [{ url: destination.url, token: registered.token, sharing: { ...SYSTEM_DEFAULT_SHARING } }]
6333
6557
  };
6334
6558
  writeCollectorIdentity(collectorStatePath2(paths), adopted);
6335
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6559
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6336
6560
  return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
6337
6561
  }
6338
6562
  }
@@ -6340,7 +6564,7 @@ async function pairCollectorWithHub(options) {
6340
6564
  try {
6341
6565
  grant = createLocalEnrollmentGrant(paths, host);
6342
6566
  } catch (error2) {
6343
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6567
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6344
6568
  return {
6345
6569
  paired: false,
6346
6570
  awaiting: true,
@@ -6358,18 +6582,18 @@ async function pairCollectorWithHub(options) {
6358
6582
  note: `enrollment through the live hub failed: ${error2 instanceof Error ? error2.message : String(error2)}`
6359
6583
  };
6360
6584
  } finally {
6361
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6585
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6362
6586
  }
6363
6587
  if (!collectorConfigured(paths).configured) {
6364
6588
  return { paired: false, awaiting: true, hubWasActive, note: "the hub accepted enrollment but no destination was saved" };
6365
6589
  }
6366
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6590
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6367
6591
  return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
6368
6592
  }
6369
6593
  const identity = {
6370
- collectorId: existing?.collectorId ?? (0, import_node_crypto11.randomUUID)(),
6371
- machineId: (0, import_node_crypto11.randomUUID)(),
6372
- token: (0, import_node_crypto11.randomBytes)(32).toString("base64url")
6594
+ collectorId: existing?.collectorId ?? (0, import_node_crypto12.randomUUID)(),
6595
+ machineId: (0, import_node_crypto12.randomUUID)(),
6596
+ token: (0, import_node_crypto12.randomBytes)(32).toString("base64url")
6373
6597
  };
6374
6598
  const registry = registerCollectorInHubDatabase(paths, identity, host);
6375
6599
  let token = identity.token;
@@ -6396,7 +6620,7 @@ async function pairCollectorWithHub(options) {
6396
6620
  }
6397
6621
  ];
6398
6622
  writeCollectorIdentity(collectorStatePath2(paths), next);
6399
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6623
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
6400
6624
  return { paired: true, awaiting: false, hubWasActive, destination: destination.url };
6401
6625
  }
6402
6626
  function unitCommon(name, description, paths, account, envPath, execStart, extraService = []) {
@@ -6413,7 +6637,7 @@ function unitCommon(name, description, paths, account, envPath, execStart, extra
6413
6637
  "Type=simple",
6414
6638
  `User=${account}`,
6415
6639
  `Group=${account}`,
6416
- `WorkingDirectory=${(0, import_node_path18.join)(paths.prefix, "current").replace(/%/g, "%%")}`,
6640
+ `WorkingDirectory=${(0, import_node_path19.join)(paths.prefix, "current").replace(/%/g, "%%")}`,
6417
6641
  `EnvironmentFile=${envPath.replace(/%/g, "%%")}`,
6418
6642
  "Environment=NODE_ENV=production",
6419
6643
  "Restart=on-failure",
@@ -6448,13 +6672,13 @@ function unitCommon(name, description, paths, account, envPath, execStart, extra
6448
6672
  }
6449
6673
  function renderSystemHubUnit(options) {
6450
6674
  const { paths, accounts } = options;
6451
- const hubScript = (0, import_node_path18.join)(paths.prefix, "current", "dist", "hub.cjs");
6675
+ const hubScript = (0, import_node_path19.join)(paths.prefix, "current", "dist", "hub.cjs");
6452
6676
  const extra = [
6453
6677
  `Environment=${systemdQuote(`HUB_DATABASE_PATH=${options.database}`)}`,
6454
6678
  `Environment=${systemdQuote(`HUB_STATE_FILE=${options.enrollment}`)}`,
6455
6679
  ...options.remote ? [`Environment=${systemdQuote(`HUB_SOCKET_PATH=${options.socket}`)}`] : [],
6456
- `ReadWritePaths=${systemdQuote((0, import_node_path18.join)(paths.stateDir, "hub"))}`,
6457
- `ReadOnlyPaths=${systemdQuote((0, import_node_path18.join)(paths.prefix, "current"))}`,
6680
+ `ReadWritePaths=${systemdQuote((0, import_node_path19.join)(paths.stateDir, "hub"))}`,
6681
+ `ReadOnlyPaths=${systemdQuote((0, import_node_path19.join)(paths.prefix, "current"))}`,
6458
6682
  "PrivateDevices=yes",
6459
6683
  "TimeoutStopSec=15s"
6460
6684
  ];
@@ -6473,14 +6697,14 @@ function renderSystemHubUnit(options) {
6473
6697
  }
6474
6698
  function renderSystemCollectorUnit(options) {
6475
6699
  const { paths, accounts } = options;
6476
- const collectorScript = (0, import_node_path18.join)(paths.prefix, "current", "dist", "collector.cjs");
6700
+ const collectorScript = (0, import_node_path19.join)(paths.prefix, "current", "dist", "collector.cjs");
6477
6701
  const extra = [
6478
6702
  ...options.powerAccess ? [`SupplementaryGroups=${accounts.powerGroup}`] : [],
6479
6703
  `Environment=${systemdQuote(`COLLECTOR_MODE=real`)}`,
6480
6704
  `Environment=${systemdQuote(`COLLECTOR_STATE_FILE=${options.collectorState}`)}`,
6481
- `Environment=${systemdQuote(`COLLECTOR_HEALTH_FILE=${(0, import_node_path18.join)(paths.stateDir, "collector", "health.json")}`)}`,
6482
- `ReadWritePaths=${systemdQuote((0, import_node_path18.join)(paths.stateDir, "collector"))}`,
6483
- `ReadOnlyPaths=${systemdQuote((0, import_node_path18.join)(paths.prefix, "current"))}`,
6705
+ `Environment=${systemdQuote(`COLLECTOR_HEALTH_FILE=${(0, import_node_path19.join)(paths.stateDir, "collector", "health.json")}`)}`,
6706
+ `ReadWritePaths=${systemdQuote((0, import_node_path19.join)(paths.stateDir, "collector"))}`,
6707
+ `ReadOnlyPaths=${systemdQuote((0, import_node_path19.join)(paths.prefix, "current"))}`,
6484
6708
  "TimeoutStopSec=10s"
6485
6709
  ];
6486
6710
  return [
@@ -6553,11 +6777,15 @@ function collectorEnvTemplate() {
6553
6777
  "# COLLECTOR_ENROLL_URL=ws://127.0.0.1:8081/api/collector/connect",
6554
6778
  "# COLLECTOR_ENROLL_TOKEN=<one-use grant>",
6555
6779
  "# COLLECTOR_MODE=real",
6780
+ "# Unacknowledged samples wait in RAM by default: no queue is written to disk",
6781
+ "# and a collector restart loses what was never acknowledged. Set this to durable",
6782
+ "# to keep them in a per-hub SQLite outbox across collector restarts.",
6783
+ "# COLLECTOR_QUEUE_MODE=durable",
6556
6784
  ""
6557
6785
  ].join("\n");
6558
6786
  }
6559
6787
  function assertPrivateSourceFile(path2, label3) {
6560
- const stat = (0, import_node_fs16.lstatSync)(path2);
6788
+ const stat = (0, import_node_fs17.lstatSync)(path2);
6561
6789
  if (!stat.isFile() || stat.isSymbolicLink()) {
6562
6790
  throw new SystemError("unsafe-adoption", `${label3} must be a regular file: ${path2}`);
6563
6791
  }
@@ -6568,7 +6796,7 @@ function assertPrivateSourceFile(path2, label3) {
6568
6796
  function readJsonObject(path2) {
6569
6797
  let raw;
6570
6798
  try {
6571
- raw = (0, import_node_fs16.readFileSync)(path2, "utf8");
6799
+ raw = (0, import_node_fs17.readFileSync)(path2, "utf8");
6572
6800
  } catch (error2) {
6573
6801
  throw new SystemError("missing-file", `cannot read ${path2}: ${error2.message}`);
6574
6802
  }
@@ -6591,8 +6819,8 @@ function isCanonicalComponents(value) {
6591
6819
  }
6592
6820
  function readSystemState(paths) {
6593
6821
  const path2 = stateFilePath(paths);
6594
- if (!(0, import_node_fs16.existsSync)(path2)) return null;
6595
- const stat = (0, import_node_fs16.lstatSync)(path2);
6822
+ if (!(0, import_node_fs17.existsSync)(path2)) return null;
6823
+ const stat = (0, import_node_fs17.lstatSync)(path2);
6596
6824
  if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("unsafe-path", `${path2} must be a regular file`);
6597
6825
  if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `${path2} must be 0600`);
6598
6826
  const raw = readJsonObject(path2);
@@ -6624,7 +6852,7 @@ function readSystemState(paths) {
6624
6852
  }
6625
6853
  function systemStateIsLegacy(paths) {
6626
6854
  const path2 = stateFilePath(paths);
6627
- if (!(0, import_node_fs16.existsSync)(path2)) return false;
6855
+ if (!(0, import_node_fs17.existsSync)(path2)) return false;
6628
6856
  let raw;
6629
6857
  try {
6630
6858
  raw = readJsonObject(path2);
@@ -6675,24 +6903,24 @@ function validateVersion2(value) {
6675
6903
  return value;
6676
6904
  }
6677
6905
  function releaseVersion(root) {
6678
- const metadata = readJsonObject((0, import_node_path18.join)(root, "package.json"));
6906
+ const metadata = readJsonObject((0, import_node_path19.join)(root, "package.json"));
6679
6907
  if (Object.hasOwn(metadata, "rigscopeConfigVersion")) {
6680
6908
  throw new SystemError("invalid-release", "release uses unfinished configuration metadata; select a canonical release");
6681
6909
  }
6682
6910
  return validateVersion2(metadata.version);
6683
6911
  }
6684
6912
  function releaseSchemaVersion(root) {
6685
- const manifestPath = (0, import_node_path18.join)(root, "manifest.json");
6686
- if (!(0, import_node_fs16.existsSync)(manifestPath)) return null;
6913
+ const manifestPath = (0, import_node_path19.join)(root, "manifest.json");
6914
+ if (!(0, import_node_fs17.existsSync)(manifestPath)) return null;
6687
6915
  const manifest = readJsonObject(manifestPath);
6688
6916
  return Number.isSafeInteger(manifest.schemaVersion) ? Number(manifest.schemaVersion) : null;
6689
6917
  }
6690
6918
  function assertReleaseArtifacts(root) {
6691
6919
  for (const artifact of REQUIRED_ARTIFACTS) {
6692
- const path2 = (0, import_node_path18.join)(root, artifact);
6920
+ const path2 = (0, import_node_path19.join)(root, artifact);
6693
6921
  let stat;
6694
6922
  try {
6695
- stat = (0, import_node_fs16.lstatSync)(path2);
6923
+ stat = (0, import_node_fs17.lstatSync)(path2);
6696
6924
  } catch {
6697
6925
  throw new SystemError("missing-artifact", `release is missing ${artifact}`);
6698
6926
  }
@@ -6700,12 +6928,12 @@ function assertReleaseArtifacts(root) {
6700
6928
  throw new SystemError("invalid-artifact", `release artifact is not a non-empty regular file: ${artifact}`);
6701
6929
  }
6702
6930
  }
6703
- const buildId = (0, import_node_fs16.readFileSync)((0, import_node_path18.join)(root, ".next", "BUILD_ID"), "utf8").trim();
6931
+ const buildId = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(root, ".next", "BUILD_ID"), "utf8").trim();
6704
6932
  if (buildId === "" || /\s/.test(buildId)) throw new SystemError("invalid-artifact", ".next/BUILD_ID is invalid");
6705
6933
  for (const directory of [".next/server", ".next/static"]) {
6706
6934
  let stat;
6707
6935
  try {
6708
- stat = (0, import_node_fs16.lstatSync)((0, import_node_path18.join)(root, directory));
6936
+ stat = (0, import_node_fs17.lstatSync)((0, import_node_path19.join)(root, directory));
6709
6937
  } catch {
6710
6938
  throw new SystemError("missing-artifact", `release is missing ${directory}/`);
6711
6939
  }
@@ -6713,10 +6941,10 @@ function assertReleaseArtifacts(root) {
6713
6941
  }
6714
6942
  }
6715
6943
  function verifyReleaseManifest(root) {
6716
- const manifestPath = (0, import_node_path18.join)(root, "manifest.json");
6717
- if (!(0, import_node_fs16.existsSync)(manifestPath)) return;
6944
+ const manifestPath = (0, import_node_path19.join)(root, "manifest.json");
6945
+ if (!(0, import_node_fs17.existsSync)(manifestPath)) return;
6718
6946
  const manifest = readJsonObject(manifestPath);
6719
- const packageJson = readJsonObject((0, import_node_path18.join)(root, "package.json"));
6947
+ const packageJson = readJsonObject((0, import_node_path19.join)(root, "package.json"));
6720
6948
  if (manifest.name !== void 0 && manifest.name !== packageJson.name) {
6721
6949
  throw new SystemError("manifest-mismatch", "release manifest name does not match package.json");
6722
6950
  }
@@ -6735,17 +6963,17 @@ function verifyReleaseManifest(root) {
6735
6963
  if (typeof relativePath !== "string" || relativePath === "" || relativePath.startsWith("/") || relativePath.includes("\\") || relativePath.split("/").includes("..")) {
6736
6964
  throw new SystemError("invalid-manifest", `release manifest contains an unsafe path: ${String(relativePath)}`);
6737
6965
  }
6738
- const absolute = (0, import_node_path18.join)(root, relativePath);
6739
- const stat = (0, import_node_fs16.lstatSync)(absolute);
6966
+ const absolute = (0, import_node_path19.join)(root, relativePath);
6967
+ const stat = (0, import_node_fs17.lstatSync)(absolute);
6740
6968
  if (!stat.isFile() || stat.isSymbolicLink()) throw new SystemError("invalid-manifest", `release artifact is not a regular file: ${relativePath}`);
6741
6969
  if (entry2.bytes !== stat.size) throw new SystemError("artifact-mismatch", `release artifact size changed: ${relativePath}`);
6742
6970
  if (entry2.sha256 !== sha256File2(absolute)) throw new SystemError("artifact-mismatch", `release artifact hash changed: ${relativePath}`);
6743
6971
  listed.add(relativePath);
6744
6972
  }
6745
6973
  const visit = (current) => {
6746
- for (const entry2 of (0, import_node_fs16.readdirSync)(current, { withFileTypes: true })) {
6747
- const absolute = (0, import_node_path18.join)(current, entry2.name);
6748
- const rel = (0, import_node_path18.relative)(root, absolute).split(import_node_path18.sep).join("/");
6974
+ for (const entry2 of (0, import_node_fs17.readdirSync)(current, { withFileTypes: true })) {
6975
+ const absolute = (0, import_node_path19.join)(current, entry2.name);
6976
+ const rel = (0, import_node_path19.relative)(root, absolute).split(import_node_path19.sep).join("/");
6749
6977
  if (rel === "node_modules" || rel.startsWith("node_modules/") || rel === ".next/cache" || rel.startsWith(".next/cache/")) continue;
6750
6978
  if (entry2.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${rel}`);
6751
6979
  if (entry2.isDirectory()) {
@@ -6760,49 +6988,49 @@ function verifyReleaseManifest(root) {
6760
6988
  }
6761
6989
  function assertNoSymlinks(root) {
6762
6990
  const visit = (path2) => {
6763
- const stat = (0, import_node_fs16.lstatSync)(path2);
6764
- if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${(0, import_node_path18.relative)(root, path2)}`);
6991
+ const stat = (0, import_node_fs17.lstatSync)(path2);
6992
+ if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `release contains a symlink: ${(0, import_node_path19.relative)(root, path2)}`);
6765
6993
  if (!stat.isDirectory()) return;
6766
- for (const entry2 of (0, import_node_fs16.readdirSync)(path2)) visit((0, import_node_path18.join)(path2, entry2));
6994
+ for (const entry2 of (0, import_node_fs17.readdirSync)(path2)) visit((0, import_node_path19.join)(path2, entry2));
6767
6995
  };
6768
6996
  visit(root);
6769
6997
  }
6770
6998
  function copyReleaseTree(source, destination) {
6771
6999
  const visit = (current, target) => {
6772
- const stat = (0, import_node_fs16.lstatSync)(current);
6773
- if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${(0, import_node_path18.relative)(source, current)}`);
7000
+ const stat = (0, import_node_fs17.lstatSync)(current);
7001
+ if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${(0, import_node_path19.relative)(source, current)}`);
6774
7002
  if (stat.isDirectory()) {
6775
- (0, import_node_fs16.mkdirSync)(target, { recursive: true, mode: 493 });
6776
- for (const entry2 of (0, import_node_fs16.readdirSync)(current)) {
6777
- const child = (0, import_node_path18.join)(current, entry2);
6778
- const rel = (0, import_node_path18.relative)(source, child);
7003
+ (0, import_node_fs17.mkdirSync)(target, { recursive: true, mode: 493 });
7004
+ for (const entry2 of (0, import_node_fs17.readdirSync)(current)) {
7005
+ const child = (0, import_node_path19.join)(current, entry2);
7006
+ const rel = (0, import_node_path19.relative)(source, child);
6779
7007
  if (rel === ".git" || rel === ".next-dev" || rel === ".next/cache" || rel === "node_modules" || rel.startsWith("node_modules/")) {
6780
7008
  continue;
6781
7009
  }
6782
- visit(child, (0, import_node_path18.join)(target, entry2));
7010
+ visit(child, (0, import_node_path19.join)(target, entry2));
6783
7011
  }
6784
7012
  return;
6785
7013
  }
6786
- if (!stat.isFile()) throw new SystemError("unsafe-release", `source contains a non-regular file: ${(0, import_node_path18.relative)(source, current)}`);
6787
- (0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(target), { recursive: true, mode: 493 });
6788
- (0, import_node_fs16.copyFileSync)(current, target);
6789
- (0, import_node_fs16.chmodSync)(target, 420);
7014
+ if (!stat.isFile()) throw new SystemError("unsafe-release", `source contains a non-regular file: ${(0, import_node_path19.relative)(source, current)}`);
7015
+ (0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(target), { recursive: true, mode: 493 });
7016
+ (0, import_node_fs17.copyFileSync)(current, target);
7017
+ (0, import_node_fs17.chmodSync)(target, 420);
6790
7018
  };
6791
7019
  visit(source, destination);
6792
7020
  }
6793
7021
  function copyReleaseAllowlisted(source, destination) {
6794
- for (const entry2 of (0, import_node_fs16.readdirSync)(source)) {
7022
+ for (const entry2 of (0, import_node_fs17.readdirSync)(source)) {
6795
7023
  if (!PACKAGE_TOP_LEVEL.has(entry2)) continue;
6796
7024
  if (entry2 === "node_modules") continue;
6797
- const child = (0, import_node_path18.join)(source, entry2);
6798
- const target = (0, import_node_path18.join)(destination, entry2);
6799
- const stat = (0, import_node_fs16.lstatSync)(child);
7025
+ const child = (0, import_node_path19.join)(source, entry2);
7026
+ const target = (0, import_node_path19.join)(destination, entry2);
7027
+ const stat = (0, import_node_fs17.lstatSync)(child);
6800
7028
  if (stat.isSymbolicLink()) throw new SystemError("unsafe-release", `source contains a symlink: ${entry2}`);
6801
7029
  if (stat.isDirectory()) {
6802
7030
  copyReleaseTree(child, target);
6803
7031
  } else if (stat.isFile()) {
6804
- (0, import_node_fs16.copyFileSync)(child, target);
6805
- (0, import_node_fs16.chmodSync)(target, 420);
7032
+ (0, import_node_fs17.copyFileSync)(child, target);
7033
+ (0, import_node_fs17.chmodSync)(target, 420);
6806
7034
  }
6807
7035
  }
6808
7036
  }
@@ -6837,28 +7065,28 @@ function extractArchive(archive, stage, host) {
6837
7065
  }
6838
7066
  function discardStagedRelease(staged) {
6839
7067
  if (staged === null) return;
6840
- (0, import_node_fs16.rmSync)(staged.stageDir, { recursive: true, force: true });
7068
+ (0, import_node_fs17.rmSync)(staged.stageDir, { recursive: true, force: true });
6841
7069
  }
6842
7070
  function releaseTargetDir(paths, version) {
6843
- return (0, import_node_path18.join)(paths.prefix, "releases", version);
7071
+ return (0, import_node_path19.join)(paths.prefix, "releases", version);
6844
7072
  }
6845
7073
  function assertReleaseTargetAvailable(paths, releaseDir, replaceRelease) {
6846
- if (!(0, import_node_fs16.existsSync)(releaseDir)) return;
7074
+ if (!(0, import_node_fs17.existsSync)(releaseDir)) return;
6847
7075
  const current = currentReleaseDir(paths);
6848
7076
  const previous = previousReleaseDir(paths);
6849
7077
  if (!replaceRelease || current === releaseDir || previous === releaseDir) {
6850
7078
  throw new SystemError(
6851
7079
  "release-exists",
6852
- `release ${(0, import_node_path18.basename)(releaseDir)} is already installed${current === releaseDir || previous === releaseDir ? " or retained" : ""}; choose a new version`
7080
+ `release ${(0, import_node_path19.basename)(releaseDir)} is already installed${current === releaseDir || previous === releaseDir ? " or retained" : ""}; choose a new version`
6853
7081
  );
6854
7082
  }
6855
7083
  }
6856
7084
  function stageRelease(options) {
6857
- const source = (0, import_node_fs16.realpathSync)((0, import_node_path18.resolve)(options.source));
6858
- const stat = (0, import_node_fs16.lstatSync)(source);
7085
+ const source = (0, import_node_fs17.realpathSync)((0, import_node_path19.resolve)(options.source));
7086
+ const stat = (0, import_node_fs17.lstatSync)(source);
6859
7087
  ensureDirectory(options.paths.prefix, 493);
6860
- const stageDir = (0, import_node_path18.join)(options.paths.prefix, `.stage-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
6861
- (0, import_node_fs16.mkdirSync)(stageDir, { recursive: true, mode: 448 });
7088
+ const stageDir = (0, import_node_path19.join)(options.paths.prefix, `.stage-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
7089
+ (0, import_node_fs17.mkdirSync)(stageDir, { recursive: true, mode: 448 });
6862
7090
  try {
6863
7091
  if (stat.isDirectory() && !stat.isSymbolicLink()) {
6864
7092
  copyReleaseAllowlisted(source, stageDir);
@@ -6876,7 +7104,7 @@ function stageRelease(options) {
6876
7104
  artifacts: [...REQUIRED_ARTIFACTS]
6877
7105
  };
6878
7106
  } catch (error2) {
6879
- (0, import_node_fs16.rmSync)(stageDir, { recursive: true, force: true });
7107
+ (0, import_node_fs17.rmSync)(stageDir, { recursive: true, force: true });
6880
7108
  throw error2;
6881
7109
  }
6882
7110
  }
@@ -6902,13 +7130,13 @@ function prepareStagedRelease(options) {
6902
7130
  }
6903
7131
  }
6904
7132
  function commitStagedRelease(options) {
6905
- const releasesDir = (0, import_node_path18.join)(options.paths.prefix, "releases");
7133
+ const releasesDir = (0, import_node_path19.join)(options.paths.prefix, "releases");
6906
7134
  ensureDirectory(releasesDir, 493);
6907
7135
  const releaseDir = releaseTargetDir(options.paths, options.staged.version);
6908
7136
  assertReleaseTargetAvailable(options.paths, releaseDir, options.replaceRelease);
6909
- if ((0, import_node_fs16.existsSync)(releaseDir)) (0, import_node_fs16.rmSync)(releaseDir, { recursive: true, force: true });
6910
- (0, import_node_fs16.renameSync)(options.staged.stageDir, releaseDir);
6911
- ensureDirectory((0, import_node_path18.join)(releaseDir, ".next", "cache"), 493);
7137
+ if ((0, import_node_fs17.existsSync)(releaseDir)) (0, import_node_fs17.rmSync)(releaseDir, { recursive: true, force: true });
7138
+ (0, import_node_fs17.renameSync)(options.staged.stageDir, releaseDir);
7139
+ ensureDirectory((0, import_node_path19.join)(releaseDir, ".next", "cache"), 493);
6912
7140
  return {
6913
7141
  version: options.staged.version,
6914
7142
  releaseDir,
@@ -6917,20 +7145,20 @@ function commitStagedRelease(options) {
6917
7145
  };
6918
7146
  }
6919
7147
  function dependencyNames(root) {
6920
- const pkg = readJsonObject((0, import_node_path18.join)(root, "package.json"));
7148
+ const pkg = readJsonObject((0, import_node_path19.join)(root, "package.json"));
6921
7149
  const dependencies2 = pkg.dependencies;
6922
7150
  if (dependencies2 === null || typeof dependencies2 !== "object" || Array.isArray(dependencies2)) return [];
6923
7151
  return Object.keys(dependencies2).filter((name) => /^[A-Za-z0-9@/._-]+$/.test(name));
6924
7152
  }
6925
7153
  function missingDependencies(root) {
6926
- return dependencyNames(root).filter((name) => !(0, import_node_fs16.existsSync)((0, import_node_path18.join)(root, "node_modules", name, "package.json")));
7154
+ return dependencyNames(root).filter((name) => !(0, import_node_fs17.existsSync)((0, import_node_path19.join)(root, "node_modules", name, "package.json")));
6927
7155
  }
6928
7156
  function installDependencies(root, host, command = "npm") {
6929
- const hasLock = (0, import_node_fs16.existsSync)((0, import_node_path18.join)(root, "package-lock.json"));
7157
+ const hasLock = (0, import_node_fs17.existsSync)((0, import_node_path19.join)(root, "package-lock.json"));
6930
7158
  const args = hasLock ? ["ci", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"] : ["install", "--omit=dev", "--ignore-scripts", "--no-audit", "--no-fund"];
6931
- const siblingNpm = (0, import_node_path18.join)((0, import_node_path18.dirname)(process.execPath), "npm");
6932
- const executable = command === "npm" && (0, import_node_fs16.existsSync)(siblingNpm) ? siblingNpm : command;
6933
- const nodeBin = (0, import_node_path18.dirname)(process.execPath);
7159
+ const siblingNpm = (0, import_node_path19.join)((0, import_node_path19.dirname)(process.execPath), "npm");
7160
+ const executable = command === "npm" && (0, import_node_fs17.existsSync)(siblingNpm) ? siblingNpm : command;
7161
+ const nodeBin = (0, import_node_path19.dirname)(process.execPath);
6934
7162
  const path2 = [nodeBin, process.env.PATH ?? ""].filter(Boolean).join(":");
6935
7163
  runRequired(host, executable, args, "production dependency installation", {
6936
7164
  cwd: root,
@@ -6939,21 +7167,21 @@ function installDependencies(root, host, command = "npm") {
6939
7167
  });
6940
7168
  }
6941
7169
  function currentReleaseDir(paths) {
6942
- const link = (0, import_node_path18.join)(paths.prefix, "current");
7170
+ const link = (0, import_node_path19.join)(paths.prefix, "current");
6943
7171
  try {
6944
- const target = (0, import_node_fs16.readlinkSync)(link);
6945
- const absolute = (0, import_node_path18.isAbsolute)(target) ? target : (0, import_node_path18.resolve)(paths.prefix, target);
6946
- return isWithin((0, import_node_path18.join)(paths.prefix, "releases"), absolute) ? absolute : null;
7172
+ const target = (0, import_node_fs17.readlinkSync)(link);
7173
+ const absolute = (0, import_node_path19.isAbsolute)(target) ? target : (0, import_node_path19.resolve)(paths.prefix, target);
7174
+ return isWithin((0, import_node_path19.join)(paths.prefix, "releases"), absolute) ? absolute : null;
6947
7175
  } catch {
6948
7176
  return null;
6949
7177
  }
6950
7178
  }
6951
7179
  function previousReleaseDir(paths) {
6952
- const link = (0, import_node_path18.join)(paths.prefix, "previous");
7180
+ const link = (0, import_node_path19.join)(paths.prefix, "previous");
6953
7181
  try {
6954
- const target = (0, import_node_fs16.readlinkSync)(link);
6955
- const absolute = (0, import_node_path18.isAbsolute)(target) ? target : (0, import_node_path18.resolve)(paths.prefix, target);
6956
- return isWithin((0, import_node_path18.join)(paths.prefix, "releases"), absolute) ? absolute : null;
7182
+ const target = (0, import_node_fs17.readlinkSync)(link);
7183
+ const absolute = (0, import_node_path19.isAbsolute)(target) ? target : (0, import_node_path19.resolve)(paths.prefix, target);
7184
+ return isWithin((0, import_node_path19.join)(paths.prefix, "releases"), absolute) ? absolute : null;
6957
7185
  } catch {
6958
7186
  return null;
6959
7187
  }
@@ -6961,11 +7189,11 @@ function previousReleaseDir(paths) {
6961
7189
  function replaceSymlink(link, target, host) {
6962
7190
  const temporary = `${link}.tmp-${process.pid}-${Date.now()}`;
6963
7191
  try {
6964
- (0, import_node_fs16.symlinkSync)(target, temporary);
6965
- (0, import_node_fs16.renameSync)(temporary, link);
7192
+ (0, import_node_fs17.symlinkSync)(target, temporary);
7193
+ (0, import_node_fs17.renameSync)(temporary, link);
6966
7194
  } catch (error2) {
6967
7195
  try {
6968
- (0, import_node_fs16.unlinkSync)(temporary);
7196
+ (0, import_node_fs17.unlinkSync)(temporary);
6969
7197
  } catch {
6970
7198
  }
6971
7199
  throw error2;
@@ -6974,8 +7202,8 @@ function replaceSymlink(link, target, host) {
6974
7202
  }
6975
7203
  function removeSymlink(link) {
6976
7204
  try {
6977
- const stat = (0, import_node_fs16.lstatSync)(link);
6978
- if (stat.isSymbolicLink()) (0, import_node_fs16.unlinkSync)(link);
7205
+ const stat = (0, import_node_fs17.lstatSync)(link);
7206
+ if (stat.isSymbolicLink()) (0, import_node_fs17.unlinkSync)(link);
6979
7207
  } catch {
6980
7208
  }
6981
7209
  }
@@ -6988,18 +7216,18 @@ function nodeVersion(host, nodePath) {
6988
7216
  return output;
6989
7217
  }
6990
7218
  function ensureRootOwnedNode(options) {
6991
- const selected = (0, import_node_path18.resolve)(options.nodePath ?? process.execPath);
6992
- const real = (0, import_node_fs16.realpathSync)(selected);
7219
+ const selected = (0, import_node_path19.resolve)(options.nodePath ?? process.execPath);
7220
+ const real = (0, import_node_fs17.realpathSync)(selected);
6993
7221
  nodeVersion(options.host, real);
6994
- const stat = (0, import_node_fs16.statSync)(real);
6995
- const insideRelease = isWithin((0, import_node_path18.join)(options.paths.prefix, "releases"), real);
7222
+ const stat = (0, import_node_fs17.statSync)(real);
7223
+ const insideRelease = isWithin((0, import_node_path19.join)(options.paths.prefix, "releases"), real);
6996
7224
  const unsafe = stat.uid !== 0 || (stat.mode & 18) !== 0 || options.copyNode === true || insideRelease;
6997
7225
  if (!unsafe || options.trustedNode === true) return real;
6998
- const target = (0, import_node_path18.join)(options.paths.prefix, "node", "node");
7226
+ const target = (0, import_node_path19.join)(options.paths.prefix, "node", "node");
6999
7227
  if (!options.apply) return target;
7000
- ensureDirectory((0, import_node_path18.join)(options.paths.prefix, "node"), 493);
7001
- (0, import_node_fs16.copyFileSync)(real, target);
7002
- (0, import_node_fs16.chmodSync)(target, 493);
7228
+ ensureDirectory((0, import_node_path19.join)(options.paths.prefix, "node"), 493);
7229
+ (0, import_node_fs17.copyFileSync)(real, target);
7230
+ (0, import_node_fs17.chmodSync)(target, 493);
7003
7231
  runRequired(options.host, "chown", ["root:root", target], "node ownership");
7004
7232
  nodeVersion(options.host, target);
7005
7233
  return target;
@@ -7028,8 +7256,8 @@ function validatedOrigin(value) {
7028
7256
  return value;
7029
7257
  }
7030
7258
  function readAdoptionSetup(source) {
7031
- const configPath = (0, import_node_path18.join)(source, "config.json");
7032
- if (!(0, import_node_fs16.existsSync)(configPath)) {
7259
+ const configPath = (0, import_node_path19.join)(source, "config.json");
7260
+ if (!(0, import_node_fs17.existsSync)(configPath)) {
7033
7261
  throw new SystemError("invalid-adoption", "adopted installation has no config.json");
7034
7262
  }
7035
7263
  assertPrivateSourceFile(configPath, "adopted setup");
@@ -7077,35 +7305,35 @@ function detectUserInstallations(options = {}) {
7077
7305
  const roots = options.homeRoots ?? ["/home", "/root"];
7078
7306
  const found = [];
7079
7307
  for (const homeRoot of roots) {
7080
- if (!(0, import_node_fs16.existsSync)(homeRoot)) continue;
7081
- const homes = homeRoot === "/root" ? ["/root"] : (0, import_node_fs16.readdirSync)(homeRoot).map((entry2) => (0, import_node_path18.join)(homeRoot, entry2));
7308
+ if (!(0, import_node_fs17.existsSync)(homeRoot)) continue;
7309
+ const homes = homeRoot === "/root" ? ["/root"] : (0, import_node_fs17.readdirSync)(homeRoot).map((entry2) => (0, import_node_path19.join)(homeRoot, entry2));
7082
7310
  for (const home of homes) {
7083
7311
  let stat;
7084
7312
  try {
7085
- stat = (0, import_node_fs16.lstatSync)(home);
7313
+ stat = (0, import_node_fs17.lstatSync)(home);
7086
7314
  } catch {
7087
7315
  continue;
7088
7316
  }
7089
7317
  if (!stat.isDirectory()) continue;
7090
- const unitDir = (0, import_node_path18.join)(home, ".config", "systemd", "user");
7318
+ const unitDir = (0, import_node_path19.join)(home, ".config", "systemd", "user");
7091
7319
  let units = [];
7092
7320
  try {
7093
- units = (0, import_node_fs16.readdirSync)(unitDir);
7321
+ units = (0, import_node_fs17.readdirSync)(unitDir);
7094
7322
  } catch {
7095
7323
  units = [];
7096
7324
  }
7097
7325
  for (const unitName2 of units) {
7098
7326
  if (!/^rigscope(?:-[0-9a-f]{12})?(?:-(?:hub|collector))?\.service$/.test(unitName2)) continue;
7099
- const unitPath2 = (0, import_node_path18.join)(unitDir, unitName2);
7327
+ const unitPath2 = (0, import_node_path19.join)(unitDir, unitName2);
7100
7328
  let execStart = null;
7101
7329
  try {
7102
- const line = (0, import_node_fs16.readFileSync)(unitPath2, "utf8").split("\n").find((item) => item.startsWith("ExecStart="));
7330
+ const line = (0, import_node_fs17.readFileSync)(unitPath2, "utf8").split("\n").find((item) => item.startsWith("ExecStart="));
7103
7331
  execStart = line ? line.slice("ExecStart=".length) : null;
7104
7332
  } catch {
7105
7333
  }
7106
- const stateCandidates = [(0, import_node_path18.join)(home, ".local", "state", "rigscope")];
7107
- const stateDir = stateCandidates.find((candidate) => (0, import_node_fs16.existsSync)(candidate)) ?? null;
7108
- found.push({ user: (0, import_node_path18.basename)(home), home, unitPath: unitPath2, unitName: unitName2, execStart, stateDir });
7334
+ const stateCandidates = [(0, import_node_path19.join)(home, ".local", "state", "rigscope")];
7335
+ const stateDir = stateCandidates.find((candidate) => (0, import_node_fs17.existsSync)(candidate)) ?? null;
7336
+ found.push({ user: (0, import_node_path19.basename)(home), home, unitPath: unitPath2, unitName: unitName2, execStart, stateDir });
7109
7337
  }
7110
7338
  }
7111
7339
  }
@@ -7113,9 +7341,9 @@ function detectUserInstallations(options = {}) {
7113
7341
  }
7114
7342
  function lockIsLive(path2) {
7115
7343
  try {
7116
- const stat = (0, import_node_fs16.lstatSync)(path2);
7344
+ const stat = (0, import_node_fs17.lstatSync)(path2);
7117
7345
  if (!stat.isFile() || stat.size > 4096) return { exists: true, live: false, pid: null, ambiguous: true };
7118
- const owner = JSON.parse((0, import_node_fs16.readFileSync)(path2, "utf8"));
7346
+ const owner = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
7119
7347
  const pid = owner.pid;
7120
7348
  if (!Number.isSafeInteger(pid) || pid < 1) return { exists: true, live: false, pid: null, ambiguous: true };
7121
7349
  try {
@@ -7133,9 +7361,9 @@ function lockIsLive(path2) {
7133
7361
  }
7134
7362
  function directoryLocks(directory) {
7135
7363
  return [
7136
- (0, import_node_path18.join)(directory, "hub", "telemetry.sqlite.hub.lock"),
7137
- (0, import_node_path18.join)(directory, "run", "rigscope.lock"),
7138
- (0, import_node_path18.join)(directory, "collector", "collector-runtime.lock")
7364
+ (0, import_node_path19.join)(directory, "hub", "telemetry.sqlite.hub.lock"),
7365
+ (0, import_node_path19.join)(directory, "run", "rigscope.lock"),
7366
+ (0, import_node_path19.join)(directory, "collector", "collector-runtime.lock")
7139
7367
  ];
7140
7368
  }
7141
7369
  function assertDirectoryStopped(directory, scope = "local") {
@@ -7166,13 +7394,13 @@ function assertSystemStartAllowed(paths, components) {
7166
7394
  }
7167
7395
  function detectPowerDriver(moduleRoot = "/sys/module") {
7168
7396
  const candidates = ["intel_rapl_msr", "intel_rapl_common", "intel_rapl_tpmi", "intel_rapl", "amd_energy"];
7169
- return candidates.filter((name) => (0, import_node_fs16.existsSync)((0, import_node_path18.join)(moduleRoot, name)));
7397
+ return candidates.filter((name) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(moduleRoot, name)));
7170
7398
  }
7171
7399
  function readPasswd(path2 = "/etc/passwd") {
7172
7400
  const users = /* @__PURE__ */ new Map();
7173
7401
  let lines;
7174
7402
  try {
7175
- lines = (0, import_node_fs16.readFileSync)(path2, "utf8").split("\n");
7403
+ lines = (0, import_node_fs17.readFileSync)(path2, "utf8").split("\n");
7176
7404
  } catch {
7177
7405
  return users;
7178
7406
  }
@@ -7189,7 +7417,7 @@ function readGroups(path2 = "/etc/group") {
7189
7417
  const groups = /* @__PURE__ */ new Map();
7190
7418
  let lines;
7191
7419
  try {
7192
- lines = (0, import_node_fs16.readFileSync)(path2, "utf8").split("\n");
7420
+ lines = (0, import_node_fs17.readFileSync)(path2, "utf8").split("\n");
7193
7421
  } catch {
7194
7422
  return groups;
7195
7423
  }
@@ -7217,7 +7445,7 @@ function inspectPowerAccess(options = {}) {
7217
7445
  const sysusers = options.sysusersPath ?? powerSysusersPath(paths);
7218
7446
  let ruleText = null;
7219
7447
  try {
7220
- ruleText = (0, import_node_fs16.readFileSync)(rulePath, "utf8");
7448
+ ruleText = (0, import_node_fs17.readFileSync)(rulePath, "utf8");
7221
7449
  } catch {
7222
7450
  ruleText = null;
7223
7451
  }
@@ -7234,27 +7462,27 @@ function inspectPowerAccess(options = {}) {
7234
7462
  const domains = [];
7235
7463
  let entries = [];
7236
7464
  try {
7237
- entries = (0, import_node_fs16.readdirSync)(paths.powercapRoot);
7465
+ entries = (0, import_node_fs17.readdirSync)(paths.powercapRoot);
7238
7466
  } catch {
7239
7467
  entries = [];
7240
7468
  }
7241
7469
  for (const entry2 of entries.filter((name) => /^intel-rapl:\d+$/.test(name)).sort()) {
7242
- const domainPath = (0, import_node_path18.join)(paths.powercapRoot, entry2);
7470
+ const domainPath = (0, import_node_path19.join)(paths.powercapRoot, entry2);
7243
7471
  let name = entry2;
7244
7472
  try {
7245
- name = (0, import_node_fs16.readFileSync)((0, import_node_path18.join)(domainPath, "name"), "utf8").trim() || entry2;
7473
+ name = (0, import_node_fs17.readFileSync)((0, import_node_path19.join)(domainPath, "name"), "utf8").trim() || entry2;
7246
7474
  } catch {
7247
7475
  }
7248
7476
  if (!/^package/.test(name)) continue;
7249
- const energyPath = (0, import_node_path18.join)(domainPath, "energy_uj");
7250
- const maxRangePath = (0, import_node_path18.join)(domainPath, "max_energy_range_uj");
7477
+ const energyPath = (0, import_node_path19.join)(domainPath, "energy_uj");
7478
+ const maxRangePath = (0, import_node_path19.join)(domainPath, "max_energy_range_uj");
7251
7479
  const readStat = (path2) => {
7252
7480
  if (options.statOverride) {
7253
7481
  const override = options.statOverride(path2);
7254
7482
  return override === null ? null : { mode: modeString(override.mode), uid: override.uid, gid: override.gid };
7255
7483
  }
7256
7484
  try {
7257
- const stat = (0, import_node_fs16.statSync)(path2);
7485
+ const stat = (0, import_node_fs17.statSync)(path2);
7258
7486
  return { mode: modeString(stat.mode), uid: stat.uid, gid: stat.gid };
7259
7487
  } catch {
7260
7488
  return null;
@@ -7288,7 +7516,7 @@ function inspectPowerAccess(options = {}) {
7288
7516
  problems.push(`collector account ${accounts.collector} is not a member of ${accounts.powerGroup}`);
7289
7517
  }
7290
7518
  if (!compliant) problems.push(`persistent udev rule is missing or not compliant: ${rulePath}`);
7291
- if (!(0, import_node_fs16.existsSync)(sysusers)) problems.push(`power sysusers definition is missing: ${sysusers}`);
7519
+ if (!(0, import_node_fs17.existsSync)(sysusers)) problems.push(`power sysusers definition is missing: ${sysusers}`);
7292
7520
  for (const domain of domains) {
7293
7521
  if (!domain.energyExists) problems.push(`${domain.name}: energy_uj is unavailable`);
7294
7522
  else if (domain.energy?.worldReadable) problems.push(`${domain.name}: energy_uj is world-readable`);
@@ -7307,7 +7535,7 @@ function inspectPowerAccess(options = {}) {
7307
7535
  collectorGids,
7308
7536
  group: { name: accounts.powerGroup, exists: group !== null, gid: group?.gid ?? null, members: group?.members ?? [] },
7309
7537
  rule: { path: rulePath, present: ruleText !== null, compliant },
7310
- sysusers: { path: sysusers, present: (0, import_node_fs16.existsSync)(sysusers) },
7538
+ sysusers: { path: sysusers, present: (0, import_node_fs17.existsSync)(sysusers) },
7311
7539
  collectorCanRead,
7312
7540
  persistent: compliant && group !== null && collector !== null && group.members.includes(accounts.collector),
7313
7541
  worldReadable,
@@ -7316,14 +7544,14 @@ function inspectPowerAccess(options = {}) {
7316
7544
  };
7317
7545
  }
7318
7546
  async function backupDatabase2(source, output, host) {
7319
- ensureDirectory((0, import_node_path18.dirname)(output), 448, true);
7547
+ ensureDirectory((0, import_node_path19.dirname)(output), 448, true);
7320
7548
  const db = new import_node_sqlite4.DatabaseSync(source, { readOnly: true, timeout: 5e3 });
7321
7549
  try {
7322
7550
  await (0, import_node_sqlite4.backup)(db, output);
7323
7551
  } finally {
7324
7552
  db.close();
7325
7553
  }
7326
- (0, import_node_fs16.chmodSync)(output, 384);
7554
+ (0, import_node_fs17.chmodSync)(output, 384);
7327
7555
  const check = new import_node_sqlite4.DatabaseSync(output, { readOnly: true });
7328
7556
  try {
7329
7557
  const result = check.prepare("PRAGMA integrity_check").get();
@@ -7334,7 +7562,7 @@ async function backupDatabase2(source, output, host) {
7334
7562
  void host;
7335
7563
  }
7336
7564
  function databaseSchema(path2) {
7337
- if (!(0, import_node_fs16.existsSync)(path2)) return null;
7565
+ if (!(0, import_node_fs17.existsSync)(path2)) return null;
7338
7566
  const db = new import_node_sqlite4.DatabaseSync(path2, { readOnly: true, timeout: 5e3 });
7339
7567
  try {
7340
7568
  const table = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_migrations'").get();
@@ -7353,28 +7581,28 @@ function replaceDatabaseFromBackup(backupPath, target, safetyBackup, host) {
7353
7581
  } finally {
7354
7582
  backup3.close();
7355
7583
  }
7356
- ensureDirectory((0, import_node_path18.dirname)(target), 448, true);
7357
- if (safetyBackup !== null && (0, import_node_fs16.existsSync)(target)) {
7584
+ ensureDirectory((0, import_node_path19.dirname)(target), 448, true);
7585
+ if (safetyBackup !== null && (0, import_node_fs17.existsSync)(target)) {
7358
7586
  void host;
7359
7587
  }
7360
- const temporary = (0, import_node_path18.join)((0, import_node_path18.dirname)(target), `.restore-${process.pid}-${Date.now()}.sqlite`);
7361
- (0, import_node_fs16.copyFileSync)(backupPath, temporary);
7362
- (0, import_node_fs16.chmodSync)(temporary, 384);
7588
+ const temporary = (0, import_node_path19.join)((0, import_node_path19.dirname)(target), `.restore-${process.pid}-${Date.now()}.sqlite`);
7589
+ (0, import_node_fs17.copyFileSync)(backupPath, temporary);
7590
+ (0, import_node_fs17.chmodSync)(temporary, 384);
7363
7591
  for (const sidecar of [`${target}-wal`, `${target}-shm`]) {
7364
7592
  try {
7365
- (0, import_node_fs16.unlinkSync)(sidecar);
7593
+ (0, import_node_fs17.unlinkSync)(sidecar);
7366
7594
  } catch {
7367
7595
  }
7368
7596
  }
7369
- (0, import_node_fs16.renameSync)(temporary, target);
7370
- (0, import_node_fs16.chmodSync)(target, 384);
7597
+ (0, import_node_fs17.renameSync)(temporary, target);
7598
+ (0, import_node_fs17.chmodSync)(target, 384);
7371
7599
  }
7372
7600
  function newestTimestamp() {
7373
7601
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7374
7602
  }
7375
7603
  function adoptUserState(options) {
7376
- const source = (0, import_node_path18.resolve)(options.source);
7377
- if (!(0, import_node_fs16.existsSync)(source)) throw new SystemError("invalid-adoption", `user installation does not exist: ${source}`);
7604
+ const source = (0, import_node_path19.resolve)(options.source);
7605
+ if (!(0, import_node_fs17.existsSync)(source)) throw new SystemError("invalid-adoption", `user installation does not exist: ${source}`);
7378
7606
  if (isWithin(options.paths.prefix, source) || isWithin(options.paths.stateDir, source) || isWithin(source, options.paths.stateDir)) {
7379
7607
  throw new SystemError("invalid-adoption", "adoption source and system paths must not overlap");
7380
7608
  }
@@ -7384,8 +7612,8 @@ function adoptUserState(options) {
7384
7612
  const { port, origin } = setup;
7385
7613
  if (!Number.isInteger(port) || port < 1 || port > 65535) throw new SystemError("invalid-adoption", "adopted hub port is invalid");
7386
7614
  if (options.role !== "collector") {
7387
- const sourceDatabase = (0, import_node_path18.join)(source, "hub", "telemetry.sqlite");
7388
- if ((0, import_node_fs16.existsSync)(sourceDatabase)) {
7615
+ const sourceDatabase = (0, import_node_path19.join)(source, "hub", "telemetry.sqlite");
7616
+ if ((0, import_node_fs17.existsSync)(sourceDatabase)) {
7389
7617
  assertPrivateSourceFile(sourceDatabase, "adopted database");
7390
7618
  const database = new import_node_sqlite4.DatabaseSync(sourceDatabase, { readOnly: true });
7391
7619
  try {
@@ -7395,12 +7623,12 @@ function adoptUserState(options) {
7395
7623
  database.close();
7396
7624
  }
7397
7625
  }
7398
- const sourceEnrollment = (0, import_node_path18.join)(source, "hub", "enrollment.json");
7399
- if ((0, import_node_fs16.existsSync)(sourceEnrollment)) assertPrivateSourceFile(sourceEnrollment, "adopted enrollment");
7626
+ const sourceEnrollment = (0, import_node_path19.join)(source, "hub", "enrollment.json");
7627
+ if ((0, import_node_fs17.existsSync)(sourceEnrollment)) assertPrivateSourceFile(sourceEnrollment, "adopted enrollment");
7400
7628
  }
7401
7629
  if (options.role !== "hub") {
7402
- const sourceCollectorState = (0, import_node_path18.join)(source, "collector", "state.json");
7403
- if ((0, import_node_fs16.existsSync)(sourceCollectorState)) {
7630
+ const sourceCollectorState = (0, import_node_path19.join)(source, "collector", "state.json");
7631
+ if ((0, import_node_fs17.existsSync)(sourceCollectorState)) {
7404
7632
  assertPrivateSourceFile(sourceCollectorState, "adopted collector state");
7405
7633
  readCollectorIdentity(sourceCollectorState);
7406
7634
  }
@@ -7409,7 +7637,7 @@ function adoptUserState(options) {
7409
7637
  const warnings = [];
7410
7638
  const targetDatabase = hubDatabasePath(options.paths);
7411
7639
  const targetCollector = collectorStatePath2(options.paths);
7412
- if (options.apply && (0, import_node_fs16.existsSync)(targetDatabase)) {
7640
+ if (options.apply && (0, import_node_fs17.existsSync)(targetDatabase)) {
7413
7641
  throw new SystemError("destination-exists", `refusing to overwrite ${targetDatabase}`);
7414
7642
  }
7415
7643
  const hubEnv = options.role === "collector" ? null : [
@@ -7444,62 +7672,42 @@ function adoptUserState(options) {
7444
7672
  port
7445
7673
  };
7446
7674
  }
7447
- function copyAdoptedTree(source, target, copied, skipLocks = true) {
7448
- const visit = (current, destination) => {
7449
- const stat = (0, import_node_fs16.lstatSync)(current);
7450
- if (stat.isSymbolicLink()) return;
7451
- if (stat.isDirectory()) {
7452
- (0, import_node_fs16.mkdirSync)(destination, { recursive: true, mode: 448 });
7453
- for (const entry2 of (0, import_node_fs16.readdirSync)(current)) visit((0, import_node_path18.join)(current, entry2), (0, import_node_path18.join)(destination, entry2));
7454
- return;
7455
- }
7456
- if (!stat.isFile()) return;
7457
- if (skipLocks && /\.(lock|sock)$/.test(current)) return;
7458
- (0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(destination), { recursive: true, mode: 448 });
7459
- (0, import_node_fs16.copyFileSync)(current, destination);
7460
- (0, import_node_fs16.chmodSync)(destination, 384);
7461
- copied.push({ source: current, target: destination, sha256: sha256File2(destination), bytes: stat.size });
7462
- };
7463
- visit(source, target);
7464
- }
7465
7675
  async function performAdoptionCopyAsync(options) {
7466
7676
  const { source, paths, role, host, copy } = options;
7467
7677
  assertDirectoryStopped(source, role);
7468
7678
  const targetDatabase = hubDatabasePath(paths);
7469
- const sourceDatabase = (0, import_node_path18.join)(source, "hub", "telemetry.sqlite");
7470
- if (role !== "collector" && (0, import_node_fs16.existsSync)(sourceDatabase) && !(0, import_node_fs16.existsSync)(targetDatabase)) {
7679
+ const sourceDatabase = (0, import_node_path19.join)(source, "hub", "telemetry.sqlite");
7680
+ if (role !== "collector" && (0, import_node_fs17.existsSync)(sourceDatabase) && !(0, import_node_fs17.existsSync)(targetDatabase)) {
7471
7681
  assertPrivateSourceFile(sourceDatabase, "adopted database");
7472
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "hub"), 448, true);
7682
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
7473
7683
  await backupDatabase2(sourceDatabase, targetDatabase, host);
7474
7684
  copy.record.files.push({
7475
7685
  source: sourceDatabase,
7476
7686
  target: targetDatabase,
7477
7687
  sha256: sha256File2(targetDatabase),
7478
- bytes: (0, import_node_fs16.statSync)(targetDatabase).size
7688
+ bytes: (0, import_node_fs17.statSync)(targetDatabase).size
7479
7689
  });
7480
7690
  }
7481
- const sourceCollectorState = (0, import_node_path18.join)(source, "collector", "state.json");
7482
- if (role !== "hub" && (0, import_node_fs16.existsSync)(sourceCollectorState)) {
7691
+ const sourceCollectorState = (0, import_node_path19.join)(source, "collector", "state.json");
7692
+ if (role !== "hub" && (0, import_node_fs17.existsSync)(sourceCollectorState)) {
7483
7693
  assertPrivateSourceFile(sourceCollectorState, "adopted collector state");
7484
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "collector"), 448, true);
7694
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
7485
7695
  const targetCollector = collectorStatePath2(paths);
7486
- (0, import_node_fs16.copyFileSync)(sourceCollectorState, targetCollector);
7487
- (0, import_node_fs16.chmodSync)(targetCollector, 384);
7696
+ (0, import_node_fs17.copyFileSync)(sourceCollectorState, targetCollector);
7697
+ (0, import_node_fs17.chmodSync)(targetCollector, 384);
7488
7698
  copy.record.files.push({
7489
7699
  source: sourceCollectorState,
7490
7700
  target: targetCollector,
7491
7701
  sha256: sha256File2(targetCollector),
7492
- bytes: (0, import_node_fs16.statSync)(targetCollector).size
7702
+ bytes: (0, import_node_fs17.statSync)(targetCollector).size
7493
7703
  });
7494
- const outbox = (0, import_node_path18.join)(source, "collector", "outbox");
7495
- if ((0, import_node_fs16.existsSync)(outbox)) copyAdoptedTree(outbox, (0, import_node_path18.join)(paths.stateDir, "collector", "outbox"), copy.record.files);
7496
7704
  }
7497
- const enrollment = (0, import_node_path18.join)(source, "hub", "enrollment.json");
7498
- if (role !== "collector" && (0, import_node_fs16.existsSync)(enrollment)) {
7705
+ const enrollment = (0, import_node_path19.join)(source, "hub", "enrollment.json");
7706
+ if (role !== "collector" && (0, import_node_fs17.existsSync)(enrollment)) {
7499
7707
  const target = hubEnrollmentPath(paths);
7500
- (0, import_node_fs16.copyFileSync)(enrollment, target);
7501
- (0, import_node_fs16.chmodSync)(target, 384);
7502
- copy.record.files.push({ source: enrollment, target, sha256: sha256File2(target), bytes: (0, import_node_fs16.statSync)(target).size });
7708
+ (0, import_node_fs17.copyFileSync)(enrollment, target);
7709
+ (0, import_node_fs17.chmodSync)(target, 384);
7710
+ copy.record.files.push({ source: enrollment, target, sha256: sha256File2(target), bytes: (0, import_node_fs17.statSync)(target).size });
7503
7711
  }
7504
7712
  }
7505
7713
  function writeSysusersFiles(paths, accounts, role, power, host) {
@@ -7539,15 +7747,15 @@ function writePowerRule(paths, accounts) {
7539
7747
  writeManagedFile(raplRulePath(paths), renderRaplRule(accounts), 420, true);
7540
7748
  }
7541
7749
  function powerOriginalPath(paths) {
7542
- return (0, import_node_path18.join)(paths.stateDir, POWER_STATE_FILE_NAME);
7750
+ return (0, import_node_path19.join)(paths.stateDir, POWER_STATE_FILE_NAME);
7543
7751
  }
7544
7752
  function capturePowerOriginals(paths) {
7545
7753
  const files = {};
7546
7754
  for (const domain of packageDomainPaths(paths.powercapRoot)) {
7547
7755
  for (const name of ["energy_uj", "max_energy_range_uj"]) {
7548
- const path2 = (0, import_node_path18.join)(domain, name);
7756
+ const path2 = (0, import_node_path19.join)(domain, name);
7549
7757
  try {
7550
- const stat = (0, import_node_fs16.statSync)(path2);
7758
+ const stat = (0, import_node_fs17.statSync)(path2);
7551
7759
  files[path2] = { mode: stat.mode & 511, uid: stat.uid, gid: stat.gid };
7552
7760
  } catch {
7553
7761
  }
@@ -7559,8 +7767,8 @@ function capturePowerOriginals(paths) {
7559
7767
  function applyPowerAccess(paths, accounts, host) {
7560
7768
  for (const domain of packageDomainPaths(paths.powercapRoot)) {
7561
7769
  for (const name of ["energy_uj", "max_energy_range_uj"]) {
7562
- const path2 = (0, import_node_path18.join)(domain, name);
7563
- if (!(0, import_node_fs16.existsSync)(path2)) continue;
7770
+ const path2 = (0, import_node_path19.join)(domain, name);
7771
+ if (!(0, import_node_fs17.existsSync)(path2)) continue;
7564
7772
  runRequired(host, "chgrp", [accounts.powerGroup, path2], `power counter group ${path2}`);
7565
7773
  runRequired(host, "chmod", ["0440", path2], `power counter mode ${path2}`);
7566
7774
  }
@@ -7573,9 +7781,9 @@ function resumePowerRule(paths, host) {
7573
7781
  }
7574
7782
  function packageDomainPaths(root) {
7575
7783
  try {
7576
- return (0, import_node_fs16.readdirSync)(root).filter((entry2) => /^intel-rapl:\d+$/.test(entry2)).map((entry2) => (0, import_node_path18.join)(root, entry2)).filter((path2) => {
7784
+ return (0, import_node_fs17.readdirSync)(root).filter((entry2) => /^intel-rapl:\d+$/.test(entry2)).map((entry2) => (0, import_node_path19.join)(root, entry2)).filter((path2) => {
7577
7785
  try {
7578
- return /^package/.test((0, import_node_fs16.readFileSync)((0, import_node_path18.join)(path2, "name"), "utf8").trim());
7786
+ return /^package/.test((0, import_node_fs17.readFileSync)((0, import_node_path19.join)(path2, "name"), "utf8").trim());
7579
7787
  } catch {
7580
7788
  return false;
7581
7789
  }
@@ -7595,8 +7803,8 @@ function restorePowerOriginals(paths, host) {
7595
7803
  const files = { ...originals?.files ?? {} };
7596
7804
  for (const domain of packageDomainPaths(paths.powercapRoot)) {
7597
7805
  for (const name of ["energy_uj", "max_energy_range_uj"]) {
7598
- const path2 = (0, import_node_path18.join)(domain, name);
7599
- if (!(0, import_node_fs16.existsSync)(path2)) continue;
7806
+ const path2 = (0, import_node_path19.join)(domain, name);
7807
+ if (!(0, import_node_fs17.existsSync)(path2)) continue;
7600
7808
  const original = files[path2];
7601
7809
  if (original) {
7602
7810
  runRequired(host, "chown", [`${original.uid}:${original.gid}`, path2], "restore counter ownership");
@@ -7612,7 +7820,7 @@ function restorePowerOriginals(paths, host) {
7612
7820
  }
7613
7821
  }
7614
7822
  try {
7615
- (0, import_node_fs16.unlinkSync)(powerOriginalPath(paths));
7823
+ (0, import_node_fs17.unlinkSync)(powerOriginalPath(paths));
7616
7824
  } catch {
7617
7825
  }
7618
7826
  return restored;
@@ -7636,7 +7844,7 @@ function stopUnits(host, units) {
7636
7844
  if (units.some((unit) => systemdActive(host, unit))) throw new SystemError("service-active", "system services did not stop; no files were restored");
7637
7845
  }
7638
7846
  function unitsForCleanup(paths, host) {
7639
- const legacy = LEGACY_UNIT_NAMES.filter((unit) => (0, import_node_fs16.existsSync)((0, import_node_path18.join)(paths.unitsDir, unit)) || systemdActive(host, unit));
7847
+ const legacy = LEGACY_UNIT_NAMES.filter((unit) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit)) || systemdActive(host, unit));
7640
7848
  return [...Object.values(UNIT_NAMES), ...legacy];
7641
7849
  }
7642
7850
  function startUnits(host, units) {
@@ -7674,7 +7882,7 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
7674
7882
  const report = runRequired(
7675
7883
  host,
7676
7884
  state.nodePath,
7677
- [(0, import_node_path18.join)(paths.prefix, "current/dist/ops.cjs"), "inspect", "--database", hubDatabasePath(paths), "--json"],
7885
+ [(0, import_node_path19.join)(paths.prefix, "current/dist/ops.cjs"), "inspect", "--database", hubDatabasePath(paths), "--json"],
7678
7886
  "activated database verification",
7679
7887
  { timeoutMs: Math.max(100, deadline - Date.now()) }
7680
7888
  );
@@ -7690,8 +7898,8 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
7690
7898
  let problem = "no sampling marker";
7691
7899
  while (Date.now() < deadline) {
7692
7900
  try {
7693
- const marker = readJsonObject((0, import_node_path18.join)(paths.stateDir, "collector/health.json"));
7694
- const lease = readJsonObject((0, import_node_path18.join)(paths.stateDir, "collector/collector-runtime.lock"));
7901
+ const marker = readJsonObject((0, import_node_path19.join)(paths.stateDir, "collector/health.json"));
7902
+ const lease = readJsonObject((0, import_node_path19.join)(paths.stateDir, "collector/collector-runtime.lock"));
7695
7903
  if (marker.pid !== lease.pid || !Number.isSafeInteger(marker.pid)) throw new Error("sampling marker belongs to another process");
7696
7904
  process.kill(Number(marker.pid), 0);
7697
7905
  if (marker.version !== state.currentVersion || !Number.isFinite(marker.sampledAt) || Date.now() - Number(marker.sampledAt) > 15e3) throw new Error("collector version or sampling freshness is wrong");
@@ -7706,12 +7914,12 @@ async function verifySystemHealth(paths, state, host, timeoutMs, components = en
7706
7914
  }
7707
7915
  function chownAccount(paths, owner, group, host) {
7708
7916
  for (const path2 of paths) {
7709
- if (!(0, import_node_fs16.existsSync)(path2)) continue;
7917
+ if (!(0, import_node_fs17.existsSync)(path2)) continue;
7710
7918
  runRequired(host, "chown", ["-R", `${owner}:${group}`, path2], `ownership ${path2}`);
7711
7919
  }
7712
7920
  }
7713
7921
  function chmodTree(path2, host) {
7714
- if (!(0, import_node_fs16.existsSync)(path2)) return;
7922
+ if (!(0, import_node_fs17.existsSync)(path2)) return;
7715
7923
  runRequired(host, "chmod", ["-R", "u=rwX,go=rX", path2], `release permissions ${path2}`);
7716
7924
  }
7717
7925
  function pickRollbackBackup(state, previousSchema) {
@@ -7722,9 +7930,12 @@ function pickRollbackBackup(state, previousSchema) {
7722
7930
  async function recoverFailedUpgrade(options) {
7723
7931
  stopUnits(options.host, options.units);
7724
7932
  assertDirectoryStopped(options.paths.stateDir);
7725
- replaceSymlink((0, import_node_path18.join)(options.paths.prefix, "current"), options.oldCurrent, options.host);
7726
- if (options.oldPrevious === null) removeSymlink((0, import_node_path18.join)(options.paths.prefix, "previous"));
7727
- else replaceSymlink((0, import_node_path18.join)(options.paths.prefix, "previous"), options.oldPrevious, options.host);
7933
+ for (const message of undoMachineDataCleanup(systemMachineDataPaths(options.paths), options.machineData?.stagedQueues ?? null)) {
7934
+ console.warn(`rigscope system upgrade recovery: ${message}`);
7935
+ }
7936
+ replaceSymlink((0, import_node_path19.join)(options.paths.prefix, "current"), options.oldCurrent, options.host);
7937
+ if (options.oldPrevious === null) removeSymlink((0, import_node_path19.join)(options.paths.prefix, "previous"));
7938
+ else replaceSymlink((0, import_node_path19.join)(options.paths.prefix, "previous"), options.oldPrevious, options.host);
7728
7939
  const database = hubDatabasePath(options.paths);
7729
7940
  let afterSchema = null;
7730
7941
  try {
@@ -7732,13 +7943,13 @@ async function recoverFailedUpgrade(options) {
7732
7943
  } catch {
7733
7944
  afterSchema = null;
7734
7945
  }
7735
- if (options.backupPath !== null && (0, import_node_fs16.existsSync)(options.backupPath) && (afterSchema === null || options.beforeSchema === null || afterSchema > options.beforeSchema)) {
7736
- await backupDatabase2(database, (0, import_node_path18.join)(options.paths.stateDir, "backups", `failed-upgrade-${newestTimestamp()}.sqlite`), options.host);
7946
+ if (options.backupPath !== null && (0, import_node_fs17.existsSync)(options.backupPath) && (afterSchema === null || options.beforeSchema === null || afterSchema > options.beforeSchema || options.machineData?.databaseCleared === true)) {
7947
+ await backupDatabase2(database, (0, import_node_path19.join)(options.paths.stateDir, "backups", `failed-upgrade-${newestTimestamp()}.sqlite`), options.host);
7737
7948
  replaceDatabaseFromBackup(options.backupPath, database, null, options.host);
7738
7949
  runRequired(options.host, "chown", [`${options.state.accounts.hub}:${options.state.accounts.hub}`, database], "restored database ownership");
7739
7950
  }
7740
- options.state.previousVersion = options.oldPrevious === null ? null : (0, import_node_path18.basename)(options.oldPrevious);
7741
- options.state.currentVersion = (0, import_node_path18.basename)(options.oldCurrent);
7951
+ options.state.previousVersion = options.oldPrevious === null ? null : (0, import_node_path19.basename)(options.oldPrevious);
7952
+ options.state.currentVersion = (0, import_node_path19.basename)(options.oldCurrent);
7742
7953
  writeSystemState(options.paths, options.state);
7743
7954
  if (options.activeComponents.length > 0) {
7744
7955
  startUnits(options.host, options.units);
@@ -7747,14 +7958,14 @@ async function recoverFailedUpgrade(options) {
7747
7958
  }
7748
7959
  function assertManagedFileOwnership(paths, path2) {
7749
7960
  if (!isDefaultSystemLayout(paths)) return;
7750
- if (!(0, import_node_fs16.existsSync)(path2)) return;
7751
- const stat = (0, import_node_fs16.lstatSync)(path2);
7961
+ if (!(0, import_node_fs17.existsSync)(path2)) return;
7962
+ const stat = (0, import_node_fs17.lstatSync)(path2);
7752
7963
  if (stat.isSymbolicLink() || !stat.isFile()) throw new SystemError("unsafe-path", `${path2} must be a regular managed file`);
7753
7964
  if (stat.uid !== 0) throw new SystemError("insecure-ownership", `${path2} must be root-owned before replacement`);
7754
7965
  if ((stat.mode & 18) !== 0) throw new SystemError("insecure-permissions", `${path2} must not be group/world-writable`);
7755
7966
  }
7756
7967
  function writeUnitFile(paths, unit, content, replace) {
7757
- const path2 = (0, import_node_path18.join)(paths.unitsDir, unit);
7968
+ const path2 = (0, import_node_path19.join)(paths.unitsDir, unit);
7758
7969
  assertManagedFileOwnership(paths, path2);
7759
7970
  writeManagedFile(path2, content, 420, replace);
7760
7971
  }
@@ -7769,19 +7980,19 @@ function ensureComponentSetup(options) {
7769
7980
  ensureDirectory(paths.configDir, 493);
7770
7981
  ensureDirectory(paths.stateDir, 493);
7771
7982
  ensureDirectory(paths.unitsDir, 493);
7772
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "hub"), 448, true);
7773
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "hub", "run"), 448, true);
7774
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "collector"), 448, true);
7775
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "backups"), 448, true);
7983
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
7984
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub", "run"), 448, true);
7985
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
7986
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
7776
7987
  const release = currentReleaseOrThrow(paths);
7777
7988
  void release;
7778
7989
  writeSysusersFiles(paths, accounts, "local", power, host);
7779
7990
  if (component === "hub") {
7780
- if (!(0, import_node_fs16.existsSync)(hubEnvPath(paths))) {
7991
+ if (!(0, import_node_fs17.existsSync)(hubEnvPath(paths))) {
7781
7992
  const env = hubEnvTemplate(paths);
7782
7993
  writeManagedFile(hubEnvPath(paths), env, 384, false);
7783
7994
  }
7784
- if (!(0, import_node_fs16.existsSync)((0, import_node_path18.join)(paths.unitsDir, UNIT_NAMES.hub))) {
7995
+ if (!(0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, UNIT_NAMES.hub))) {
7785
7996
  const env = readHubEnvironment(paths);
7786
7997
  const remote = env.HUB_PUBLIC_ORIGIN !== void 0 && env.HUB_PUBLIC_ORIGIN !== "";
7787
7998
  const unit = renderSystemHubUnit({
@@ -7798,7 +8009,7 @@ function ensureComponentSetup(options) {
7798
8009
  `, false);
7799
8010
  }
7800
8011
  } else {
7801
- if (!(0, import_node_fs16.existsSync)(collectorEnvPath(paths))) {
8012
+ if (!(0, import_node_fs17.existsSync)(collectorEnvPath(paths))) {
7802
8013
  writeManagedFile(collectorEnvPath(paths), collectorEnvTemplate(), 384, false);
7803
8014
  }
7804
8015
  const unit = renderSystemCollectorUnit({
@@ -7814,17 +8025,17 @@ function ensureComponentSetup(options) {
7814
8025
  const validation = runRequired(
7815
8026
  host,
7816
8027
  "systemd-analyze",
7817
- ["verify", "--man=no", (0, import_node_path18.join)(paths.unitsDir, unitFor(component))],
8028
+ ["verify", "--man=no", (0, import_node_path19.join)(paths.unitsDir, unitFor(component))],
7818
8029
  "native systemd unit validation"
7819
8030
  );
7820
8031
  if (/path is not absolute|bad unit file|fatal error|unknown (?:key|lvalue)|ignoring/i.test(validation.stderr)) {
7821
8032
  throw new SystemError("invalid-unit", "native systemd validation rejected a generated directive");
7822
8033
  }
7823
- if (component === "hub") chownAccount([(0, import_node_path18.join)(paths.stateDir, "hub")], accounts.hub, accounts.hub, host);
7824
- if (component === "collector") chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
8034
+ if (component === "hub") chownAccount([(0, import_node_path19.join)(paths.stateDir, "hub")], accounts.hub, accounts.hub, host);
8035
+ if (component === "collector") chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
7825
8036
  }
7826
8037
  function ensurePowerAccess(paths, accounts, host) {
7827
- if (!(0, import_node_fs16.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
8038
+ if (!(0, import_node_fs17.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
7828
8039
  writePowerRule(paths, accounts);
7829
8040
  resumePowerRule(paths, host);
7830
8041
  applyPowerAccess(paths, accounts, host);
@@ -7842,7 +8053,7 @@ function resetUnfinishedSystemState(options) {
7842
8053
  }
7843
8054
  function installPreset(options, role) {
7844
8055
  if (options.adoptFrom !== void 0) {
7845
- return componentSet(readAdoptionSetup((0, import_node_path18.resolve)(options.adoptFrom)).components);
8056
+ return componentSet(readAdoptionSetup((0, import_node_path19.resolve)(options.adoptFrom)).components);
7846
8057
  }
7847
8058
  return componentsForRole(role);
7848
8059
  }
@@ -7854,11 +8065,11 @@ function planSystemInstall(options) {
7854
8065
  const power = options.power !== false && preset.collector;
7855
8066
  const initial = options.enable === true ? preset : { hub: false, collector: false };
7856
8067
  const files = [
7857
- { path: (0, import_node_path18.join)(paths.prefix, "current"), mode: "symlink", purpose: "active root-owned release" },
8068
+ { path: (0, import_node_path19.join)(paths.prefix, "current"), mode: "symlink", purpose: "active root-owned release" },
7858
8069
  { path: hubEnvPath(paths), mode: "0600", purpose: "root-owned hub configuration" },
7859
8070
  { path: collectorEnvPath(paths), mode: "0600", purpose: "root-owned collector configuration" },
7860
8071
  { path: sysusersPath(paths), mode: "0644", purpose: "dedicated nologin accounts" },
7861
- ...COMPONENTS3.map((component) => ({ path: (0, import_node_path18.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }))
8072
+ ...COMPONENTS3.map((component) => ({ path: (0, import_node_path19.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }))
7862
8073
  ];
7863
8074
  if (power) {
7864
8075
  files.push({ path: raplRulePath(paths), mode: "0644", purpose: "package RAPL read rule" });
@@ -7873,7 +8084,7 @@ function planSystemInstall(options) {
7873
8084
  ];
7874
8085
  const notes = [
7875
8086
  "Nothing is changed without --apply and root.",
7876
- options.adoptFrom ? `Adopts ${(0, import_node_path18.resolve)(options.adoptFrom)} by copy only; the original user setup is preserved.` : "Existing user services are not modified.",
8087
+ options.adoptFrom ? `Adopts ${(0, import_node_path19.resolve)(options.adoptFrom)} by copy only; the original user setup is preserved.` : "Existing user services are not modified.",
7877
8088
  "One complete package: both runtimes, units and accounts are installed; --role only sets the initial enabled preset.",
7878
8089
  "Hub and collector use separate unprivileged accounts; Node gets no capabilities.",
7879
8090
  ...options.enable && preset.hub ? ["Enabling the hub creates its owner account once and prints the password once."] : [],
@@ -7906,8 +8117,8 @@ async function installSystemUnlocked(options) {
7906
8117
  `existing user service(s) detected (${detail}); stop them and use --adopt-user-state for explicit copy-based adoption`
7907
8118
  );
7908
8119
  }
7909
- const source = (0, import_node_path18.resolve)(options.source);
7910
- if (!(0, import_node_fs16.existsSync)(source)) throw new SystemError("missing-source", `release source does not exist: ${source}`);
8120
+ const source = (0, import_node_path19.resolve)(options.source);
8121
+ if (!(0, import_node_fs17.existsSync)(source)) throw new SystemError("missing-source", `release source does not exist: ${source}`);
7911
8122
  const port = options.port ?? 8081;
7912
8123
  if (!Number.isInteger(port) || port < 1 || port > 65535) throw new SystemError("invalid-argument", "--port must be 1-65535");
7913
8124
  parseHubConfig(options.origin === void 0 ? { HUB_HOST: "127.0.0.1", HUB_PORT: String(port) } : { HUB_PUBLIC_ORIGIN: options.origin, HUB_SOCKET_PATH: hubSocketPath(paths) });
@@ -7928,14 +8139,14 @@ async function installSystemUnlocked(options) {
7928
8139
  });
7929
8140
  try {
7930
8141
  if (legacy) resetUnfinishedSystemState({ paths, host, now });
7931
- ensureDirectory((0, import_node_path18.join)(paths.prefix, "releases"), 493);
8142
+ ensureDirectory((0, import_node_path19.join)(paths.prefix, "releases"), 493);
7932
8143
  ensureDirectory(paths.stateDir, 493);
7933
8144
  ensureDirectory(paths.configDir, 493);
7934
8145
  ensureDirectory(paths.unitsDir, 493);
7935
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "hub"), 448, true);
7936
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "collector"), 448, true);
7937
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "backups"), 448, true);
7938
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "hub", "run"), 448, true);
8146
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub"), 448, true);
8147
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "collector"), 448, true);
8148
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
8149
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "hub", "run"), 448, true);
7939
8150
  const release = commitStagedRelease({ staged, paths, replaceRelease: options.replaceRelease });
7940
8151
  let adoption = null;
7941
8152
  if (options.adoptFrom) {
@@ -7968,13 +8179,13 @@ async function installSystemUnlocked(options) {
7968
8179
  `, true);
7969
8180
  writeUnitFile(paths, UNIT_NAMES.collector, `${collectorUnit}
7970
8181
  `, true);
7971
- const validation = runRequired(host, "systemd-analyze", ["verify", "--man=no", ...COMPONENTS3.map((component) => (0, import_node_path18.join)(paths.unitsDir, unitFor(component)))], "native systemd unit validation");
8182
+ const validation = runRequired(host, "systemd-analyze", ["verify", "--man=no", ...COMPONENTS3.map((component) => (0, import_node_path19.join)(paths.unitsDir, unitFor(component)))], "native systemd unit validation");
7972
8183
  if (/path is not absolute|bad unit file|fatal error|unknown (?:key|lvalue)|ignoring/i.test(validation.stderr)) {
7973
8184
  throw new SystemError("invalid-unit", "native systemd validation rejected a generated directive");
7974
8185
  }
7975
8186
  if (power) ensurePowerAccess(paths, accounts, host);
7976
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "hub")], accounts.hub, accounts.hub, host);
7977
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
8187
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "hub")], accounts.hub, accounts.hub, host);
8188
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], accounts.collector, accounts.collector, host);
7978
8189
  const state = emptyState({ paths, accounts, role, components: { hub: false, collector: false }, nodePath, now });
7979
8190
  state.currentVersion = release.version;
7980
8191
  state.releases[release.version] = {
@@ -7984,7 +8195,7 @@ async function installSystemUnlocked(options) {
7984
8195
  };
7985
8196
  state.adoption = adoption?.record ?? null;
7986
8197
  state.power = power ? { enabled: true, rulePath: raplRulePath(paths), group: accounts.powerGroup } : null;
7987
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "current"), release.releaseDir, host);
8198
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), release.releaseDir, host);
7988
8199
  writeSystemState(paths, state);
7989
8200
  const wantsHub = preset.hub && (options.enable === true || options.start === true);
7990
8201
  const wantsCollector = preset.collector && (options.enable === true || options.start === true);
@@ -8010,6 +8221,7 @@ async function installSystemUnlocked(options) {
8010
8221
  await verifySystemHealth(paths, state, host, options.startupTimeoutMs ?? 2e4, started);
8011
8222
  }
8012
8223
  }
8224
+ recordMachineDataTransition(paths.stateDir, release.version, (path2, content) => atomicWrite(path2, content, 384));
8013
8225
  return {
8014
8226
  operation: "install",
8015
8227
  ok: true,
@@ -8038,14 +8250,14 @@ function systemStatus(options = {}) {
8038
8250
  } catch (error2) {
8039
8251
  stateError = error2 instanceof Error ? error2.message : String(error2);
8040
8252
  }
8041
- const presentUnits = [UNIT_NAMES.hub, UNIT_NAMES.collector].filter((unit) => (0, import_node_fs16.existsSync)((0, import_node_path18.join)(paths.unitsDir, unit)));
8253
+ const presentUnits = [UNIT_NAMES.hub, UNIT_NAMES.collector].filter((unit) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit)));
8042
8254
  const publicRole = presentUnits.length === 2 ? "local" : presentUnits[0] === UNIT_NAMES.hub ? "hub" : presentUnits[0] === UNIT_NAMES.collector ? "collector" : null;
8043
8255
  const role = state?.role ?? publicRole ?? "local";
8044
8256
  const current = currentReleaseDir(paths);
8045
8257
  let publicVersion = null;
8046
8258
  if (current) {
8047
8259
  try {
8048
- const manifest = JSON.parse((0, import_node_fs16.readFileSync)((0, import_node_path18.join)(current, "package.json"), "utf8"));
8260
+ const manifest = JSON.parse((0, import_node_fs17.readFileSync)((0, import_node_path19.join)(current, "package.json"), "utf8"));
8049
8261
  if (typeof manifest.version === "string") publicVersion = manifest.version;
8050
8262
  } catch {
8051
8263
  }
@@ -8056,7 +8268,7 @@ function systemStatus(options = {}) {
8056
8268
  const componentReports = {};
8057
8269
  for (const component of COMPONENTS3) {
8058
8270
  const unit = unitFor(component);
8059
- const present = (0, import_node_fs16.existsSync)((0, import_node_path18.join)(paths.unitsDir, unit));
8271
+ const present = (0, import_node_fs17.existsSync)((0, import_node_path19.join)(paths.unitsDir, unit));
8060
8272
  const active = present && systemdActive(host, unit);
8061
8273
  const unitEnabled2 = present && systemdEnabled(host, unit);
8062
8274
  const enabled = state !== null ? state.components[component].enabled : unitEnabled2;
@@ -8065,7 +8277,7 @@ function systemStatus(options = {}) {
8065
8277
  componentReports[component] = {
8066
8278
  component,
8067
8279
  unit,
8068
- path: (0, import_node_path18.join)(paths.unitsDir, unit),
8280
+ path: (0, import_node_path19.join)(paths.unitsDir, unit),
8069
8281
  present,
8070
8282
  enabled,
8071
8283
  unitEnabled: unitEnabled2,
@@ -8109,16 +8321,16 @@ function systemStatus(options = {}) {
8109
8321
  })),
8110
8322
  database: {
8111
8323
  path: database,
8112
- exists: (0, import_node_fs16.existsSync)(database),
8324
+ exists: (0, import_node_fs17.existsSync)(database),
8113
8325
  schema,
8114
- mode: (0, import_node_fs16.existsSync)(database) ? modeString((0, import_node_fs16.statSync)(database).mode) : null,
8326
+ mode: (0, import_node_fs17.existsSync)(database) ? modeString((0, import_node_fs17.statSync)(database).mode) : null,
8115
8327
  lock
8116
8328
  },
8117
- socket: { path: hubSocketPath(paths), exists: (0, import_node_fs16.existsSync)(hubSocketPath(paths)) },
8329
+ socket: { path: hubSocketPath(paths), exists: (0, import_node_fs17.existsSync)(hubSocketPath(paths)) },
8118
8330
  config: {
8119
8331
  dir: paths.configDir,
8120
- hubEnv: { path: hubEnvPath(paths), present: (0, import_node_fs16.existsSync)(hubEnvPath(paths)) },
8121
- collectorEnv: { path: collectorEnvPath(paths), present: (0, import_node_fs16.existsSync)(collectorEnvPath(paths)) }
8332
+ hubEnv: { path: hubEnvPath(paths), present: (0, import_node_fs17.existsSync)(hubEnvPath(paths)) },
8333
+ collectorEnv: { path: collectorEnvPath(paths), present: (0, import_node_fs17.existsSync)(collectorEnvPath(paths)) }
8122
8334
  },
8123
8335
  adoption: state?.adoption ?? null,
8124
8336
  power,
@@ -8287,7 +8499,7 @@ async function enableSystem(options) {
8287
8499
  ],
8288
8500
  files: [
8289
8501
  { path: component === "hub" ? hubEnvPath(paths) : collectorEnvPath(paths), mode: "0600", purpose: `${component} configuration` },
8290
- { path: (0, import_node_path18.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }
8502
+ { path: (0, import_node_path19.join)(paths.unitsDir, unitFor(component)), mode: "0644", purpose: `${component} boot unit` }
8291
8503
  ],
8292
8504
  notes: [
8293
8505
  "Enables only the requested component; the other component keeps running.",
@@ -8355,7 +8567,7 @@ function disableSystem(options) {
8355
8567
  accounts: state.accounts,
8356
8568
  commands: [`systemctl stop ${unitFor(component)}`, `systemctl disable ${unitFor(component)}`],
8357
8569
  files: [],
8358
- notes: ["Settings, credentials, history and outboxes are retained while the component is disabled."]
8570
+ notes: ["Settings, credentials and stored history are retained while the component is disabled; unacknowledged samples held in the collector's RAM delivery queue drain with the process."]
8359
8571
  };
8360
8572
  if (options.apply !== true) return { operation: "disable", ok: true, apply: false, message: "plan only", plan };
8361
8573
  assertApply(host);
@@ -8377,7 +8589,7 @@ function disableSystem(options) {
8377
8589
  function readPrivateToken(path2, read) {
8378
8590
  let stat;
8379
8591
  try {
8380
- stat = (0, import_node_fs16.lstatSync)(path2);
8592
+ stat = (0, import_node_fs17.lstatSync)(path2);
8381
8593
  } catch (error2) {
8382
8594
  if (error2.code === "ENOENT") {
8383
8595
  throw new SystemError("missing-grant", `grant file does not exist: ${path2}`);
@@ -8388,7 +8600,7 @@ function readPrivateToken(path2, read) {
8388
8600
  if ((stat.mode & 63) !== 0) throw new SystemError("insecure-permissions", `grant file must be private (0600): ${path2}`);
8389
8601
  if (stat.size < 1 || stat.size > 4096) throw new SystemError("invalid-token", `grant file must contain 1-4096 bytes: ${path2}`);
8390
8602
  if (!read) return void 0;
8391
- const token = (0, import_node_fs16.readFileSync)(path2, "utf8").trim();
8603
+ const token = (0, import_node_fs17.readFileSync)(path2, "utf8").trim();
8392
8604
  if (token === "" || /[\r\n\0]/.test(token) || !/^[\x21-\x7e]{1,256}$/.test(token)) {
8393
8605
  throw new SystemError("invalid-token", "grant file contains an invalid token");
8394
8606
  }
@@ -8400,7 +8612,7 @@ async function connectSystem(options) {
8400
8612
  const state = readSystemState(paths);
8401
8613
  if (state === null || !state.active) throw new SystemError("not-installed", "no active system installation; run install first");
8402
8614
  const destination = connectDestinationUrl(options.url);
8403
- const tokenFile = (0, import_node_path18.resolve)(options.tokenFile);
8615
+ const tokenFile = (0, import_node_path19.resolve)(options.tokenFile);
8404
8616
  const configured = collectorConfigured(paths);
8405
8617
  if (configured.configured) {
8406
8618
  throw new SystemError(
@@ -8448,12 +8660,12 @@ async function connectSystem(options) {
8448
8660
  `collector enrollment failed: ${error2 instanceof Error ? error2.message : String(error2)}`
8449
8661
  );
8450
8662
  } finally {
8451
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
8663
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
8452
8664
  }
8453
8665
  if (!collectorConfigured(paths).configured) {
8454
8666
  throw new SystemError("enrollment-failed", "the hub accepted enrollment but no destination was saved; check private state");
8455
8667
  }
8456
- chownAccount([(0, import_node_path18.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
8668
+ chownAccount([(0, import_node_path19.join)(paths.stateDir, "collector")], state.accounts.collector, state.accounts.collector, host);
8457
8669
  writeSystemState(paths, state);
8458
8670
  const enabled = state.components.collector.enabled;
8459
8671
  if (enabled || wasActive) {
@@ -8470,13 +8682,16 @@ async function connectSystem(options) {
8470
8682
  state
8471
8683
  };
8472
8684
  }
8685
+ function systemMachineDataPaths(paths) {
8686
+ return { database: hubDatabasePath(paths), queueTree: (0, import_node_path19.join)(paths.stateDir, "collector", "outbox") };
8687
+ }
8473
8688
  async function upgradeSystemUnlocked(options) {
8474
8689
  const host = options.host ?? createSystemHost();
8475
8690
  const now = options.now ?? Date.now;
8476
8691
  const paths = validateSystemPaths(options.paths);
8477
8692
  if (systemStateIsLegacy(paths)) {
8478
- const source2 = (0, import_node_path18.resolve)(options.source);
8479
- if (!(0, import_node_fs16.existsSync)(source2)) throw new SystemError("missing-source", `release source does not exist: ${source2}`);
8693
+ const source2 = (0, import_node_path19.resolve)(options.source);
8694
+ if (!(0, import_node_fs17.existsSync)(source2)) throw new SystemError("missing-source", `release source does not exist: ${source2}`);
8480
8695
  const role = legacySystemRole(paths);
8481
8696
  const preset = componentsForRole(role);
8482
8697
  const enable = options.enable ?? (options.start === true || unitNamesForComponents(preset).some((unit) => systemdEnabled(host, unit)));
@@ -8499,7 +8714,7 @@ async function upgradeSystemUnlocked(options) {
8499
8714
  ],
8500
8715
  files: [
8501
8716
  { path: stateFilePath(paths), mode: "0600", purpose: "canonical replacement state" },
8502
- { path: (0, import_node_path18.join)(paths.stateDir, "backups"), mode: "0700", purpose: "removed with unfinished history" }
8717
+ { path: (0, import_node_path19.join)(paths.stateDir, "backups"), mode: "0700", purpose: "removed with unfinished history" }
8503
8718
  ],
8504
8719
  notes: [
8505
8720
  "An unfinished installation is reset, not migrated; its history and credentials are removed.",
@@ -8532,6 +8747,7 @@ async function upgradeSystemUnlocked(options) {
8532
8747
  if (state === null || !state.active) throw new SystemError("not-installed", "no active system installation; run install first");
8533
8748
  const activeComponents = COMPONENTS3.filter((component) => systemdActive(host, unitFor(component)));
8534
8749
  const activeUnits = activeComponents.map(unitFor);
8750
+ const transitionPending = readMachineDataTransition(paths.stateDir) === null;
8535
8751
  const plan = {
8536
8752
  operation: "upgrade",
8537
8753
  apply: options.apply === true,
@@ -8539,19 +8755,34 @@ async function upgradeSystemUnlocked(options) {
8539
8755
  components: { hub: state.components.hub.enabled, collector: state.components.collector.enabled },
8540
8756
  paths,
8541
8757
  accounts: state.accounts,
8542
- commands: ["stage new release", ...activeUnits.map((unit) => `systemctl stop ${unit}`), "backup database", "switch current", ...activeUnits.map((unit) => `systemctl start ${unit}`)],
8543
- files: [{ path: (0, import_node_path18.join)(paths.stateDir, "backups"), mode: "0700", purpose: "pre-upgrade database backup" }],
8758
+ commands: [
8759
+ "stage new release",
8760
+ ...activeUnits.map((unit) => `systemctl stop ${unit}`),
8761
+ "backup database",
8762
+ ...transitionPending ? ["discard legacy machine data and collector queues once (irreversible after success)"] : [],
8763
+ "switch current",
8764
+ ...activeUnits.map((unit) => `systemctl start ${unit}`)
8765
+ ],
8766
+ files: [
8767
+ { path: (0, import_node_path19.join)(paths.stateDir, "backups"), mode: "0700", purpose: "pre-upgrade database backup" },
8768
+ ...transitionPending ? [{ path: (0, import_node_path19.join)(paths.stateDir, "machine-data-transition.json"), mode: "0600", purpose: "written once after the transition completes" }] : []
8769
+ ],
8544
8770
  notes: [
8545
8771
  "Staging happens before any service is stopped.",
8546
8772
  "The exact active component set is restored; --start does not start a component that was stopped.",
8547
- "A failed post-upgrade start restores the previous release and matching database backup."
8773
+ "A failed post-upgrade start restores the previous release and matching database backup.",
8774
+ ...transitionPending ? [
8775
+ "This upgrade completes the one-time RAM-first machine-data transition: telemetry rows, summaries, receipts, gaps, latest snapshots, inventory and machine-derived alert history are discarded, plus the pre-RAM-first durable collector queue. The transition's database copy restores the rows and the staged queue is renamed back if activation fails.",
8776
+ `The transition always keeps ${machineDataKeptNote()}.`,
8777
+ "Later upgrades keep the marker and preserve durable history and queues."
8778
+ ] : ["The one-time machine-data transition already completed; durable history and collector queues are preserved."]
8548
8779
  ]
8549
8780
  };
8550
8781
  if (options.apply !== true) return { operation: "upgrade", ok: true, apply: false, message: "plan only", plan };
8551
8782
  assertApply(host);
8552
8783
  assertManagedPathSafety(paths, isDefaultSystemLayout(paths));
8553
- const source = (0, import_node_path18.resolve)(options.source);
8554
- if (!(0, import_node_fs16.existsSync)(source)) throw new SystemError("missing-source", `release source does not exist: ${source}`);
8784
+ const source = (0, import_node_path19.resolve)(options.source);
8785
+ if (!(0, import_node_fs17.existsSync)(source)) throw new SystemError("missing-source", `release source does not exist: ${source}`);
8555
8786
  const staged = prepareStagedRelease({
8556
8787
  source,
8557
8788
  paths,
@@ -8570,21 +8801,22 @@ async function upgradeSystemUnlocked(options) {
8570
8801
  let backupPath = null;
8571
8802
  let beforeSchema = null;
8572
8803
  let release = null;
8804
+ let machineData = null;
8573
8805
  try {
8574
8806
  stopUnits(host, activeUnits);
8575
8807
  assertDirectoryStopped(paths.stateDir);
8576
8808
  const lock = systemLockState(paths);
8577
8809
  if (lock.live) throw new SystemError("duplicate-runtime", `hub did not stop cleanly; lock remains at ${lock.path}`);
8578
8810
  const database = hubDatabasePath(paths);
8579
- if ((0, import_node_fs16.existsSync)(database)) {
8580
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "backups"), 448, true);
8811
+ if ((0, import_node_fs17.existsSync)(database)) {
8812
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
8581
8813
  beforeSchema = databaseSchema(database);
8582
- backupPath = (0, import_node_path18.join)(paths.stateDir, "backups", `pre-upgrade-${staged.version}-${newestTimestamp()}.sqlite`);
8814
+ backupPath = (0, import_node_path19.join)(paths.stateDir, "backups", `pre-upgrade-${staged.version}-${newestTimestamp()}.sqlite`);
8583
8815
  await backupDatabase2(database, backupPath, host);
8584
8816
  }
8585
8817
  release = commitStagedRelease({ staged, paths, replaceRelease: options.replaceRelease });
8586
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "previous"), oldCurrent, host);
8587
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "current"), release.releaseDir, host);
8818
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "previous"), oldCurrent, host);
8819
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), release.releaseDir, host);
8588
8820
  state.previousVersion = state.currentVersion;
8589
8821
  state.currentVersion = release.version;
8590
8822
  state.releases[release.version] = {
@@ -8593,7 +8825,7 @@ async function upgradeSystemUnlocked(options) {
8593
8825
  installedAt: new Date(now()).toISOString()
8594
8826
  };
8595
8827
  if (backupPath !== null) {
8596
- state.backups[(0, import_node_path18.basename)(backupPath)] = {
8828
+ state.backups[(0, import_node_path19.basename)(backupPath)] = {
8597
8829
  path: backupPath,
8598
8830
  schemaVersion: beforeSchema,
8599
8831
  fromSchema: beforeSchema,
@@ -8604,6 +8836,7 @@ async function upgradeSystemUnlocked(options) {
8604
8836
  };
8605
8837
  }
8606
8838
  writeSystemState(paths, state);
8839
+ machineData = performMachineDataCleanup(paths.stateDir, systemMachineDataPaths(paths), now);
8607
8840
  if (activeComponents.length > 0) {
8608
8841
  startUnits(host, activeUnits);
8609
8842
  await verifySystemHealth(paths, state, host, options.startupTimeoutMs ?? 2e4, activeComponents);
@@ -8616,6 +8849,7 @@ async function upgradeSystemUnlocked(options) {
8616
8849
  oldPrevious,
8617
8850
  beforeSchema,
8618
8851
  backupPath,
8852
+ machineData,
8619
8853
  host,
8620
8854
  activeComponents,
8621
8855
  units: activeUnits
@@ -8623,6 +8857,10 @@ async function upgradeSystemUnlocked(options) {
8623
8857
  throw error2;
8624
8858
  }
8625
8859
  const upgraded = release;
8860
+ if (machineData !== null) {
8861
+ completeMachineDataCleanup(paths.stateDir, machineData, upgraded.version, (path2, content) => atomicWrite(path2, content, 384));
8862
+ }
8863
+ const machineHistory = machineData?.report;
8626
8864
  return {
8627
8865
  operation: "upgrade",
8628
8866
  ok: true,
@@ -8632,6 +8870,7 @@ async function upgradeSystemUnlocked(options) {
8632
8870
  current: upgraded.releaseDir,
8633
8871
  previous: oldCurrent,
8634
8872
  backupPath,
8873
+ ...machineHistory ? { machineHistory } : {},
8635
8874
  state
8636
8875
  };
8637
8876
  } finally {
@@ -8639,7 +8878,7 @@ async function upgradeSystemUnlocked(options) {
8639
8878
  }
8640
8879
  }
8641
8880
  function systemOperationLockPath(paths) {
8642
- return (0, import_node_path18.join)(paths.prefix, "run", "operation.lock");
8881
+ return (0, import_node_path19.join)(paths.prefix, "run", "operation.lock");
8643
8882
  }
8644
8883
  async function withSystemOperation(options, operation) {
8645
8884
  if (!options.apply) return operation();
@@ -8647,7 +8886,7 @@ async function withSystemOperation(options, operation) {
8647
8886
  assertApply(host);
8648
8887
  const paths = validateSystemPaths(options.paths);
8649
8888
  ensureDirectory(paths.prefix, 493);
8650
- ensureDirectory((0, import_node_path18.join)(paths.prefix, "run"), 448, true);
8889
+ ensureDirectory((0, import_node_path19.join)(paths.prefix, "run"), 448, true);
8651
8890
  const release = acquireProcessLease(systemOperationLockPath(paths));
8652
8891
  try {
8653
8892
  return await operation();
@@ -8699,24 +8938,24 @@ async function rollbackSystemUnlocked(options = {}) {
8699
8938
  try {
8700
8939
  stopUnits(host, units);
8701
8940
  assertDirectoryStopped(paths.stateDir);
8702
- if (systemLockState(paths).live || lockIsLive((0, import_node_path18.join)(paths.stateDir, "collector/collector-runtime.lock")).live) {
8941
+ if (systemLockState(paths).live || lockIsLive((0, import_node_path19.join)(paths.stateDir, "collector/collector-runtime.lock")).live) {
8703
8942
  throw new SystemError("runtime-active", "runtime lease remains after stop; rollback refused");
8704
8943
  }
8705
8944
  const database = hubDatabasePath(paths);
8706
- const currentSchema = (0, import_node_fs16.existsSync)(database) ? databaseSchema(database) : null;
8945
+ const currentSchema = (0, import_node_fs17.existsSync)(database) ? databaseSchema(database) : null;
8707
8946
  let backupToRestore = null;
8708
8947
  if (currentSchema !== null && (previousSchema === null || currentSchema > previousSchema)) {
8709
8948
  backupToRestore = pickRollbackBackup(state, previousSchema);
8710
- if (backupToRestore === null || !(0, import_node_fs16.existsSync)(backupToRestore.path)) {
8949
+ if (backupToRestore === null || !(0, import_node_fs17.existsSync)(backupToRestore.path)) {
8711
8950
  throw new SystemError(
8712
8951
  "incompatible-schema",
8713
8952
  `current database schema ${currentSchema} is newer than release ${previousVersion}; no matching pre-upgrade backup is recorded`
8714
8953
  );
8715
8954
  }
8716
8955
  }
8717
- if ((0, import_node_fs16.existsSync)(database)) {
8718
- ensureDirectory((0, import_node_path18.join)(paths.stateDir, "backups"), 448, true);
8719
- safetyBackup = (0, import_node_path18.join)(paths.stateDir, "backups", `pre-rollback-${newestTimestamp()}.sqlite`);
8956
+ if ((0, import_node_fs17.existsSync)(database)) {
8957
+ ensureDirectory((0, import_node_path19.join)(paths.stateDir, "backups"), 448, true);
8958
+ safetyBackup = (0, import_node_path19.join)(paths.stateDir, "backups", `pre-rollback-${newestTimestamp()}.sqlite`);
8720
8959
  await backupDatabase2(database, safetyBackup, host);
8721
8960
  }
8722
8961
  if (backupToRestore !== null) {
@@ -8724,8 +8963,8 @@ async function rollbackSystemUnlocked(options = {}) {
8724
8963
  restoredDatabase = true;
8725
8964
  runRequired(host, "chown", [`${state.accounts.hub}:${state.accounts.hub}`, database], "restored database ownership");
8726
8965
  }
8727
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "previous"), oldCurrent, host);
8728
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "current"), previous, host);
8966
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "previous"), oldCurrent, host);
8967
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), previous, host);
8729
8968
  state.previousVersion = state.currentVersion;
8730
8969
  state.currentVersion = previousVersion;
8731
8970
  state.updatedAt = new Date(now()).toISOString();
@@ -8747,10 +8986,10 @@ async function rollbackSystemUnlocked(options = {}) {
8747
8986
  };
8748
8987
  } catch (error2) {
8749
8988
  stopUnits(host, units);
8750
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "current"), oldCurrent, host);
8751
- replaceSymlink((0, import_node_path18.join)(paths.prefix, "previous"), previous, host);
8989
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "current"), oldCurrent, host);
8990
+ replaceSymlink((0, import_node_path19.join)(paths.prefix, "previous"), previous, host);
8752
8991
  if (restoredDatabase && safetyBackup) {
8753
- const failed = (0, import_node_path18.join)(paths.stateDir, "backups", `failed-rollback-${newestTimestamp()}.sqlite`);
8992
+ const failed = (0, import_node_path19.join)(paths.stateDir, "backups", `failed-rollback-${newestTimestamp()}.sqlite`);
8754
8993
  await backupDatabase2(hubDatabasePath(paths), failed, host);
8755
8994
  replaceDatabaseFromBackup(safetyBackup, hubDatabasePath(paths), null, host);
8756
8995
  runRequired(host, "chown", [`${state.accounts.hub}:${state.accounts.hub}`, hubDatabasePath(paths)], "restored database ownership");
@@ -8807,31 +9046,31 @@ function uninstallSystem(options = {}) {
8807
9046
  assertDirectoryStopped(paths.stateDir);
8808
9047
  for (const unit of units) runMaybe(host, "systemctl", ["disable", unit]);
8809
9048
  for (const unit of units) {
8810
- const path2 = (0, import_node_path18.join)(paths.unitsDir, unit);
9049
+ const path2 = (0, import_node_path19.join)(paths.unitsDir, unit);
8811
9050
  assertManagedFileOwnership(paths, path2);
8812
9051
  try {
8813
- (0, import_node_fs16.unlinkSync)(path2);
9052
+ (0, import_node_fs17.unlinkSync)(path2);
8814
9053
  } catch {
8815
9054
  }
8816
9055
  }
8817
9056
  runMaybe(host, "systemctl", ["daemon-reload"]);
8818
- const hadPowerAccess = state?.power?.enabled === true || (0, import_node_fs16.existsSync)(raplRulePath(paths)) || (0, import_node_fs16.existsSync)(powerOriginalPath(paths));
9057
+ const hadPowerAccess = state?.power?.enabled === true || (0, import_node_fs17.existsSync)(raplRulePath(paths)) || (0, import_node_fs17.existsSync)(powerOriginalPath(paths));
8819
9058
  if (hadPowerAccess) {
8820
9059
  try {
8821
- (0, import_node_fs16.unlinkSync)(raplRulePath(paths));
9060
+ (0, import_node_fs17.unlinkSync)(raplRulePath(paths));
8822
9061
  } catch {
8823
9062
  }
8824
9063
  try {
8825
- (0, import_node_fs16.unlinkSync)(powerSysusersPath(paths));
9064
+ (0, import_node_fs17.unlinkSync)(powerSysusersPath(paths));
8826
9065
  } catch {
8827
9066
  }
8828
9067
  restorePowerOriginals(paths, host);
8829
9068
  resumePowerRule(paths, host);
8830
9069
  }
8831
- removeSymlink((0, import_node_path18.join)(paths.prefix, "current"));
8832
- removeSymlink((0, import_node_path18.join)(paths.prefix, "previous"));
8833
- (0, import_node_fs16.rmSync)((0, import_node_path18.join)(paths.prefix, "releases"), { recursive: true, force: true });
8834
- if (options.preserveNode !== true) (0, import_node_fs16.rmSync)((0, import_node_path18.join)(paths.prefix, "node"), { recursive: true, force: true });
9070
+ removeSymlink((0, import_node_path19.join)(paths.prefix, "current"));
9071
+ removeSymlink((0, import_node_path19.join)(paths.prefix, "previous"));
9072
+ (0, import_node_fs17.rmSync)((0, import_node_path19.join)(paths.prefix, "releases"), { recursive: true, force: true });
9073
+ if (options.preserveNode !== true) (0, import_node_fs17.rmSync)((0, import_node_path19.join)(paths.prefix, "node"), { recursive: true, force: true });
8835
9074
  if (state !== null) {
8836
9075
  state.active = false;
8837
9076
  state.power = null;
@@ -8844,8 +9083,8 @@ function uninstallSystem(options = {}) {
8844
9083
  for (const group of [accounts.powerGroup, accounts.hub, accounts.collector]) runMaybe(host, "groupdel", [group]);
8845
9084
  }
8846
9085
  if (options.purgeData === true) {
8847
- (0, import_node_fs16.rmSync)(paths.stateDir, { recursive: true, force: true });
8848
- (0, import_node_fs16.rmSync)(paths.configDir, { recursive: true, force: true });
9086
+ (0, import_node_fs17.rmSync)(paths.stateDir, { recursive: true, force: true });
9087
+ (0, import_node_fs17.rmSync)(paths.configDir, { recursive: true, force: true });
8849
9088
  }
8850
9089
  return {
8851
9090
  operation: "uninstall",
@@ -8895,7 +9134,7 @@ function grantPower(options = {}) {
8895
9134
  writeManagedFile(powerSysusersPath(paths), renderPowerSysusers(paths, accounts), 420, true);
8896
9135
  runRequired(host, "systemd-sysusers", [], "power group creation");
8897
9136
  assertSystemAccounts(host, accounts, true, ["collector"]);
8898
- if (!(0, import_node_fs16.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
9137
+ if (!(0, import_node_fs17.existsSync)(powerOriginalPath(paths))) capturePowerOriginals(paths);
8899
9138
  writePowerRule(paths, accounts);
8900
9139
  resumePowerRule(paths, host);
8901
9140
  applyPowerAccess(paths, accounts, host);
@@ -8924,11 +9163,11 @@ function revokePower(options = {}) {
8924
9163
  if (options.apply !== true) return { operation: "power-revoke", ok: true, apply: false, message: "plan only", plan };
8925
9164
  assertApply(host);
8926
9165
  try {
8927
- (0, import_node_fs16.unlinkSync)(raplRulePath(paths));
9166
+ (0, import_node_fs17.unlinkSync)(raplRulePath(paths));
8928
9167
  } catch {
8929
9168
  }
8930
9169
  try {
8931
- (0, import_node_fs16.unlinkSync)(powerSysusersPath(paths));
9170
+ (0, import_node_fs17.unlinkSync)(powerSysusersPath(paths));
8932
9171
  } catch {
8933
9172
  }
8934
9173
  restorePowerOriginals(paths, host);
@@ -9144,6 +9383,12 @@ function printMutationReport(report) {
9144
9383
  console.log("then run `rigscope system connect https://<hub> --token-file <file> --apply`.");
9145
9384
  }
9146
9385
  }
9386
+ function printMachineDataOutcome(machineHistory) {
9387
+ if (machineHistory === void 0) return;
9388
+ const described = describeMachineDataReport(machineHistory);
9389
+ console.log(described.summary);
9390
+ if (described.warning) console.log(`Warning: ${described.warning}`);
9391
+ }
9147
9392
  async function runSystemCommand(argv) {
9148
9393
  const parsed = parseSystemArgs(argv);
9149
9394
  if (parsed.command === "help") {
@@ -9215,7 +9460,7 @@ ${humanPlan(report.plan)}`);
9215
9460
  if (parsed.command === "logs") {
9216
9461
  const selected = validateSystemPaths(paths);
9217
9462
  const component = componentFrom(parsed, false);
9218
- const units = (component ? [unitFor(component)] : [UNIT_NAMES.hub, UNIT_NAMES.collector]).filter((unit) => (0, import_node_fs16.existsSync)((0, import_node_path18.join)(selected.unitsDir, unit)));
9463
+ const units = (component ? [unitFor(component)] : [UNIT_NAMES.hub, UNIT_NAMES.collector]).filter((unit) => (0, import_node_fs17.existsSync)((0, import_node_path19.join)(selected.unitsDir, unit)));
9219
9464
  if (units.length === 0) throw new SystemError("not-installed", component ? `${component} logs are unavailable; its unit is not installed` : "no system services installed");
9220
9465
  const result = (0, import_node_child_process5.spawnSync)("journalctl", [...units.flatMap((unit) => ["--unit", unit]), "--lines=100", "--no-pager", ...boolValue(values, "follow") ? ["--follow"] : []], { stdio: "inherit" });
9221
9466
  if (result.error) throw result.error;
@@ -9291,6 +9536,7 @@ ${humanPlan(report.plan)}`);
9291
9536
  else {
9292
9537
  printMutationReport(report);
9293
9538
  console.log(`Backup: ${report.backupPath ?? "none"}`);
9539
+ printMachineDataOutcome(report.machineHistory);
9294
9540
  }
9295
9541
  return 0;
9296
9542
  }
@@ -9396,7 +9642,7 @@ if (isMainModule()) {
9396
9642
  }
9397
9643
 
9398
9644
  // src/cli/selection.ts
9399
- var import_node_fs17 = require("node:fs");
9645
+ var import_node_fs18 = require("node:fs");
9400
9646
  function selectInstallation(options) {
9401
9647
  if (options.scope !== void 0 && options.scope !== "user" && options.scope !== "system") {
9402
9648
  throw new Error("--scope must be user or system.");
@@ -9412,16 +9658,16 @@ function selectInstallation(options) {
9412
9658
  return options.systemPresent ? "system" : "user";
9413
9659
  }
9414
9660
  function systemInstallationPresent() {
9415
- return (0, import_node_fs17.existsSync)("/opt/rigscope/current") || (0, import_node_fs17.existsSync)("/etc/systemd/system/rigscope-hub.service") || (0, import_node_fs17.existsSync)("/etc/systemd/system/rigscope-collector.service");
9661
+ return (0, import_node_fs18.existsSync)("/opt/rigscope/current") || (0, import_node_fs18.existsSync)("/etc/systemd/system/rigscope-hub.service") || (0, import_node_fs18.existsSync)("/etc/systemd/system/rigscope-collector.service");
9416
9662
  }
9417
9663
 
9418
9664
  // src/cli/access.ts
9419
- var import_node_fs18 = require("node:fs");
9420
- var import_node_path19 = require("node:path");
9421
- var import_node_crypto13 = require("node:crypto");
9665
+ var import_node_fs19 = require("node:fs");
9666
+ var import_node_path20 = require("node:path");
9667
+ var import_node_crypto14 = require("node:crypto");
9422
9668
 
9423
9669
  // collector/destinations/outbox.ts
9424
- var import_node_crypto12 = require("node:crypto");
9670
+ var import_node_crypto13 = require("node:crypto");
9425
9671
  var path = __toESM(require("node:path"));
9426
9672
  var import_node_sqlite5 = require("node:sqlite");
9427
9673
  var DEFAULT_OUTBOX_LIMITS = {
@@ -9433,7 +9679,7 @@ var DEFAULT_OUTBOX_LIMITS = {
9433
9679
  var DEFAULT_OUTBOX_DISK_BYTES = 80 * 1024 * 1024;
9434
9680
  var WRITE_HEADROOM_BYTES = 16 * 1024;
9435
9681
  function outboxDirFor(stateDir, url) {
9436
- const digest = (0, import_node_crypto12.createHash)("sha256").update(url, "utf8").digest("hex").slice(0, 16);
9682
+ const digest = (0, import_node_crypto13.createHash)("sha256").update(url, "utf8").digest("hex").slice(0, 16);
9437
9683
  return path.join(stateDir, "outbox", digest);
9438
9684
  }
9439
9685
 
@@ -9443,7 +9689,7 @@ function endpointFor(config) {
9443
9689
  }
9444
9690
  function readCollectorState(dir) {
9445
9691
  try {
9446
- return JSON.parse(readPrivate((0, import_node_path19.join)(dir, "collector", "state.json")));
9692
+ return JSON.parse(readPrivate((0, import_node_path20.join)(dir, "collector", "state.json")));
9447
9693
  } catch (error2) {
9448
9694
  if (error2.code === "ENOENT") return null;
9449
9695
  throw error2;
@@ -9468,7 +9714,7 @@ function planAccessChange(dir, options) {
9468
9714
  delete next.socket;
9469
9715
  } else if (options.origin) {
9470
9716
  next.origin = options.origin;
9471
- next.socket = options.socket ?? (0, import_node_path19.join)(dir, "run", "hub.sock");
9717
+ next.socket = options.socket ?? (0, import_node_path20.join)(dir, "run", "hub.sock");
9472
9718
  }
9473
9719
  parseHubConfig(hubEnvironment(dir, next));
9474
9720
  const oldEndpoint = endpointFor(previous);
@@ -9484,8 +9730,8 @@ function planAccessChange(dir, options) {
9484
9730
  collectorChanged,
9485
9731
  oldEndpoint,
9486
9732
  newEndpoint,
9487
- oldQueue: collectorChanged ? outboxDirFor((0, import_node_path19.join)(dir, "collector"), oldEndpoint) : null,
9488
- newQueue: collectorChanged ? outboxDirFor((0, import_node_path19.join)(dir, "collector"), newEndpoint) : null,
9733
+ oldQueue: collectorChanged ? outboxDirFor((0, import_node_path20.join)(dir, "collector"), oldEndpoint) : null,
9734
+ newQueue: collectorChanged ? outboxDirFor((0, import_node_path20.join)(dir, "collector"), newEndpoint) : null,
9489
9735
  state,
9490
9736
  self
9491
9737
  };
@@ -9493,22 +9739,22 @@ function planAccessChange(dir, options) {
9493
9739
  function configureAccess(dir, options) {
9494
9740
  const plan = planAccessChange(dir, options);
9495
9741
  if (!plan.changed) return { changed: false, backup: null, url: plan.url };
9496
- const configPath = (0, import_node_path19.join)(dir, "config.json");
9497
- const statePath = (0, import_node_path19.join)(dir, "collector", "state.json");
9742
+ const configPath = (0, import_node_path20.join)(dir, "config.json");
9743
+ const statePath = (0, import_node_path20.join)(dir, "collector", "state.json");
9498
9744
  const beforeConfig = readPrivate(configPath);
9499
9745
  const beforeState = plan.state === null ? null : readPrivate(statePath);
9500
- if (plan.collectorChanged && plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0, import_node_fs18.existsSync)(plan.newQueue)) {
9746
+ if (plan.collectorChanged && plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0, import_node_fs19.existsSync)(plan.newQueue)) {
9501
9747
  throw new Error("The destination already has an outbox. Preserve or replay it before changing access.");
9502
9748
  }
9503
- if (plan.oldQueue && (0, import_node_fs18.existsSync)(plan.oldQueue)) {
9504
- const stat = (0, import_node_fs18.lstatSync)(plan.oldQueue);
9749
+ if (plan.oldQueue && (0, import_node_fs19.existsSync)(plan.oldQueue)) {
9750
+ const stat = (0, import_node_fs19.lstatSync)(plan.oldQueue);
9505
9751
  if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("Collector outbox must be a real directory.");
9506
9752
  }
9507
- const backup3 = (0, import_node_path19.join)(dir, "backups", `access-${(0, import_node_crypto13.randomUUID)()}`);
9753
+ const backup3 = (0, import_node_path20.join)(dir, "backups", `access-${(0, import_node_crypto14.randomUUID)()}`);
9508
9754
  privateDirectory(backup3);
9509
- writePrivateFile((0, import_node_path19.join)(backup3, "config.json"), beforeConfig);
9510
- if (beforeState !== null) writePrivateFile((0, import_node_path19.join)(backup3, "collector-state.json"), beforeState);
9511
- writePrivateFile((0, import_node_path19.join)(backup3, "change.json"), JSON.stringify({
9755
+ writePrivateFile((0, import_node_path20.join)(backup3, "config.json"), beforeConfig);
9756
+ if (beforeState !== null) writePrivateFile((0, import_node_path20.join)(backup3, "collector-state.json"), beforeState);
9757
+ writePrivateFile((0, import_node_path20.join)(backup3, "change.json"), JSON.stringify({
9512
9758
  oldEndpoint: plan.collectorChanged ? plan.oldEndpoint : null,
9513
9759
  newEndpoint: plan.collectorChanged ? plan.newEndpoint : null,
9514
9760
  oldQueue: plan.oldQueue,
@@ -9516,8 +9762,8 @@ function configureAccess(dir, options) {
9516
9762
  }));
9517
9763
  let movedQueue = false;
9518
9764
  try {
9519
- if (plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0, import_node_fs18.existsSync)(plan.oldQueue)) {
9520
- (0, import_node_fs18.renameSync)(plan.oldQueue, plan.newQueue);
9765
+ if (plan.oldQueue && plan.newQueue && plan.oldQueue !== plan.newQueue && (0, import_node_fs19.existsSync)(plan.oldQueue)) {
9766
+ (0, import_node_fs19.renameSync)(plan.oldQueue, plan.newQueue);
9521
9767
  movedQueue = true;
9522
9768
  }
9523
9769
  if (plan.collectorChanged && plan.state && plan.self) {
@@ -9533,7 +9779,7 @@ function configureAccess(dir, options) {
9533
9779
  try {
9534
9780
  writePrivateFile(configPath, beforeConfig);
9535
9781
  if (beforeState !== null) writePrivateFile(statePath, beforeState);
9536
- if (movedQueue) (0, import_node_fs18.renameSync)(plan.newQueue, plan.oldQueue);
9782
+ if (movedQueue) (0, import_node_fs19.renameSync)(plan.newQueue, plan.oldQueue);
9537
9783
  } catch {
9538
9784
  throw new Error(`Access change could not be recovered. Keep the service stopped and restore configuration from ${backup3}.`);
9539
9785
  }
@@ -9543,7 +9789,7 @@ function configureAccess(dir, options) {
9543
9789
  }
9544
9790
 
9545
9791
  // src/cli/main.ts
9546
- var ROOT = (0, import_node_path20.resolve)(__dirname, "..");
9792
+ var ROOT = (0, import_node_path21.resolve)(__dirname, "..");
9547
9793
  var HELP2 = `Rigscope \u2014 your machines, in view
9548
9794
 
9549
9795
  Usage: rigscope <command> [options]
@@ -9664,7 +9910,7 @@ async function readPassword() {
9664
9910
  }
9665
9911
  }
9666
9912
  function passwordFromFile(path2) {
9667
- const raw = readPrivate((0, import_node_path20.resolve)(path2));
9913
+ const raw = readPrivate((0, import_node_path21.resolve)(path2));
9668
9914
  return raw.replace(/\r?\n$/, "");
9669
9915
  }
9670
9916
  function healthDeadline(value) {
@@ -9705,7 +9951,12 @@ function announce(setup, dir) {
9705
9951
  Password: ${setup.password}`);
9706
9952
  printWarning("Save this password; it is shown once.");
9707
9953
  }
9708
- console.log(`Configuration: ${(0, import_node_path20.join)(dir, "config.json")}`);
9954
+ console.log(`Configuration: ${(0, import_node_path21.join)(dir, "config.json")}`);
9955
+ }
9956
+ function printMachineDataOutcome2(machineHistory) {
9957
+ const described = describeMachineDataReport(machineHistory);
9958
+ console.log(described.summary);
9959
+ if (described.warning !== null) printWarning(described.warning);
9709
9960
  }
9710
9961
  async function main() {
9711
9962
  const argv = process.argv.slice(2);
@@ -9745,7 +9996,7 @@ async function main() {
9745
9996
  return 0;
9746
9997
  }
9747
9998
  if (values.version) {
9748
- console.log(JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path20.join)(ROOT, "package.json"), "utf8")).version);
9999
+ console.log(JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path21.join)(ROOT, "package.json"), "utf8")).version);
9749
10000
  return 0;
9750
10001
  }
9751
10002
  if (process.platform !== "linux") throw new Error("Rigscope currently supports Linux.");
@@ -9777,13 +10028,13 @@ async function main() {
9777
10028
  if (value !== void 0 && key !== "state-dir" && key !== "scope" && !(permitted[command] ?? []).includes(key)) throw new Error(`--${key} is not available for ${command}.`);
9778
10029
  }
9779
10030
  if (values.origin?.endsWith("/")) values.origin = values.origin.slice(0, -1);
9780
- const managedState = (0, import_node_path20.basename)(ROOT) === "rigscope" && (0, import_node_path20.basename)((0, import_node_path20.dirname)(ROOT)) === "node_modules" && (0, import_node_path20.basename)((0, import_node_path20.resolve)(ROOT, "../..")) === "runtime" ? (0, import_node_path20.resolve)(ROOT, "../../..") : void 0;
10031
+ const managedState = (0, import_node_path21.basename)(ROOT) === "rigscope" && (0, import_node_path21.basename)((0, import_node_path21.dirname)(ROOT)) === "node_modules" && (0, import_node_path21.basename)((0, import_node_path21.resolve)(ROOT, "../..")) === "runtime" ? (0, import_node_path21.resolve)(ROOT, "../../..") : void 0;
9781
10032
  const dir = stateDirectory(values["state-dir"] ?? (command === "try" ? `${stateDirectory()}-trial` : process.env.RIGSCOPE_STATE_DIR ?? managedState));
9782
10033
  const explicitState = Boolean(values["state-dir"] || process.env.RIGSCOPE_STATE_DIR || managedState || command === "try" || command === "run");
9783
10034
  const scope = selectInstallation({
9784
10035
  scope: values.scope ?? (explicitState ? "user" : void 0),
9785
10036
  explicitState: Boolean(values["state-dir"]),
9786
- userPresent: (0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "config.json")),
10037
+ userPresent: (0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "config.json")),
9787
10038
  systemPresent: systemInstallationPresent()
9788
10039
  });
9789
10040
  if (scope === "system") {
@@ -9793,7 +10044,7 @@ async function main() {
9793
10044
  throw new Error(`System installation selected. Use rigscope system ${command} (mutations require sudo and --apply), or --scope user for a user installation.`);
9794
10045
  }
9795
10046
  if (command === "config") {
9796
- console.log((0, import_node_path20.join)(dir, "config.json"));
10047
+ console.log((0, import_node_path21.join)(dir, "config.json"));
9797
10048
  return 0;
9798
10049
  }
9799
10050
  if (command === "upgrade" && installationNeedsReset(dir)) {
@@ -9824,7 +10075,7 @@ async function main() {
9824
10075
  if (values.enable && values["no-enable"]) throw new Error("Choose --enable or --no-enable.");
9825
10076
  if (values.boot && values["no-enable"]) throw new Error("--boot requires startup to be enabled.");
9826
10077
  }
9827
- const grant = command === "connect" ? values["token-file"] ? readPrivate((0, import_node_path20.resolve)(values["token-file"])).trim() : await readGrant() : void 0;
10078
+ const grant = command === "connect" ? values["token-file"] ? readPrivate((0, import_node_path21.resolve)(values["token-file"])).trim() : await readGrant() : void 0;
9828
10079
  let recoveryPassword;
9829
10080
  if (command === "recover-password") {
9830
10081
  const saved = readSetup(dir);
@@ -9862,7 +10113,7 @@ async function main() {
9862
10113
  }
9863
10114
  if (command === "try") {
9864
10115
  if (values.role && values.role !== "local") throw new Error("Use install for a hub or collector.");
9865
- if ((0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime"))) throw new Error("This is an installed runtime. Use rigscope start, or choose a separate --state-dir for a trial.");
10116
+ if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) throw new Error("This is an installed runtime. Use rigscope start, or choose a separate --state-dir for a trial.");
9866
10117
  const setup = initialize(dir, { role: "local", port: values.port ?? "8082" });
9867
10118
  console.log("Trial: foreground hub + collector. Ctrl+C stops both.");
9868
10119
  announce(setup, dir);
@@ -9878,20 +10129,20 @@ async function main() {
9878
10129
  const releases = [];
9879
10130
  try {
9880
10131
  releases.push(acquireProcessLease(componentLeasePath(dir, "collector")));
9881
- releases.push(acquireProcessLease((0, import_node_path20.join)(dir, "collector", "collector-runtime.lock")));
9882
- await enrollCollector((0, import_node_path20.join)(dir, "collector", "state.json"), url, token, DEFAULT_SHARING, values.replace);
10132
+ releases.push(acquireProcessLease((0, import_node_path21.join)(dir, "collector", "collector-runtime.lock")));
10133
+ await enrollCollector((0, import_node_path21.join)(dir, "collector", "state.json"), url, token, DEFAULT_SHARING, values.replace);
9883
10134
  } finally {
9884
10135
  for (const release of releases.reverse()) release();
9885
10136
  }
9886
10137
  configureComponent(dir, "collector", { enabled: true, pairColocated: false });
9887
- if ((0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime"))) {
10138
+ if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
9888
10139
  writeService(dir, "collector");
9889
10140
  systemctl(dir, "enable", false, "collector");
9890
10141
  }
9891
- if (!values["no-start"] && !values["no-restart"] && (0, import_node_fs19.existsSync)(unitPath(dir, "collector"))) {
10142
+ if (!values["no-start"] && !values["no-restart"] && (0, import_node_fs20.existsSync)(unitPath(dir, "collector"))) {
9892
10143
  console.log(`Hub connected. Background service ${await startInstallation(dir, "collector")}.`);
9893
10144
  } else {
9894
- console.log(`Hub connected. Run rigscope ${(0, import_node_fs19.existsSync)(unitPath(dir, "collector")) ? "start collector" : `install --state-dir ${shellQuote2(dir)}`}.`);
10145
+ console.log(`Hub connected. Run rigscope ${(0, import_node_fs20.existsSync)(unitPath(dir, "collector")) ? "start collector" : `install --state-dir ${shellQuote2(dir)}`}.`);
9895
10146
  }
9896
10147
  return 0;
9897
10148
  }
@@ -9900,10 +10151,10 @@ async function main() {
9900
10151
  const existing = readSetup(dir);
9901
10152
  if (!existing) throw new Error("No saved installation. Run rigscope install first.");
9902
10153
  if (command === "enable") {
9903
- if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime"))) throw new Error("Install the runtime first: rigscope install --no-start.");
10154
+ if (!(0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) throw new Error("Install the runtime first: rigscope install --no-start.");
9904
10155
  if (target === "hub" && (existing.users.length > 0 || existing.origin) && (values.origin !== void 0 || values.socket !== void 0 || values.port !== void 0)) {
9905
10156
  const nextOrigin = values.origin !== void 0 ? values.origin : existing.origin;
9906
- const nextSocket = values.origin !== void 0 ? values.socket ?? (0, import_node_path20.join)(dir, "run", "hub.sock") : values.socket ?? existing.socket;
10157
+ const nextSocket = values.origin !== void 0 ? values.socket ?? (0, import_node_path21.join)(dir, "run", "hub.sock") : values.socket ?? existing.socket;
9907
10158
  const nextPort = values.port !== void 0 ? Number(values.port) : existing.port;
9908
10159
  if (nextOrigin !== existing.origin || nextSocket !== existing.socket || nextPort !== existing.port) {
9909
10160
  throw new Error("Change hub access with rigscope configure.");
@@ -9941,7 +10192,7 @@ Save this password; it is shown once.`);
9941
10192
  if (values.boot && values["no-enable"]) throw new Error("--boot requires startup to be enabled.");
9942
10193
  const resetting = installationNeedsReset(dir);
9943
10194
  if (resetting) values.role = values.role ?? installationRole(dir);
9944
- const release = resetting || serviceActive(dir) && (0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime")) ? () => {
10195
+ const release = resetting || serviceActive(dir) && (0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime")) ? () => {
9945
10196
  } : acquireProcessLease(combinedLeasePath(dir));
9946
10197
  let alias;
9947
10198
  let installedVersion;
@@ -9949,7 +10200,7 @@ Save this password; it is shown once.`);
9949
10200
  if (resetting) {
9950
10201
  console.log("Old installation state detected. Resetting configuration and history, then installing the replacement\u2026");
9951
10202
  validateSetupOptions({ role: values.role, port: values.port, origin: values.origin, socket: values.socket });
9952
- const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path20.resolve)(values.from) : values.from : void 0;
10203
+ const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path21.resolve)(values.from) : values.from : void 0;
9953
10204
  const stage = stagePackage(ROOT, dir, source);
9954
10205
  let setup;
9955
10206
  try {
@@ -9959,26 +10210,27 @@ Save this password; it is shown once.`);
9959
10210
  setup: { role: values.role, port: values.port, origin: values.origin, socket: values.socket }
9960
10211
  });
9961
10212
  } catch (error2) {
9962
- (0, import_node_fs19.rmSync)(stage, { recursive: true, force: true });
10213
+ (0, import_node_fs20.rmSync)(stage, { recursive: true, force: true });
9963
10214
  throw error2;
9964
10215
  }
9965
10216
  announce(setup, dir);
9966
- installedVersion = runtimeVersion((0, import_node_path20.join)(dir, "runtime"));
10217
+ installedVersion = runtimeVersion((0, import_node_path21.join)(dir, "runtime"));
9967
10218
  writeRuntimeState(dir, { ...readRuntimeState(dir) ?? emptyRuntimeState(dir), currentVersion: installedVersion });
9968
10219
  } else {
9969
10220
  const setup = initialize(dir, { role: values.role, port: values.port, origin: values.origin, socket: values.socket });
9970
10221
  announce(setup, dir);
9971
- if ((0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime"))) {
10222
+ if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
9972
10223
  if (values.from) throw new Error("Runtime already installed. Use rigscope upgrade --from <package>.");
9973
10224
  } else {
9974
10225
  console.log("Installing runtime\u2026");
9975
- const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path20.resolve)(values.from) : values.from : void 0;
10226
+ const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path21.resolve)(values.from) : values.from : void 0;
9976
10227
  const stage = stagePackage(ROOT, dir, source);
9977
10228
  activatePackage(dir, stage);
9978
10229
  }
9979
- installedVersion = runtimeVersion((0, import_node_path20.join)(dir, "runtime"));
10230
+ installedVersion = runtimeVersion((0, import_node_path21.join)(dir, "runtime"));
9980
10231
  writeRuntimeState(dir, { ...readRuntimeState(dir) ?? emptyRuntimeState(dir), currentVersion: installedVersion });
9981
10232
  }
10233
+ recordMachineDataTransition(dir, installedVersion);
9982
10234
  writeService(dir);
9983
10235
  alias = installAlias(dir, ROOT);
9984
10236
  const installedConfig = readSetup(dir);
@@ -10024,7 +10276,7 @@ Services: ${components2.map((target) => unitName(dir, target)).join(", ")}`);
10024
10276
  }
10025
10277
  const startup = startupStatus(dir);
10026
10278
  console.log(`Startup: ${!startup.enabled ? "manual" : startup.linger ? "at boot; continues after logout" : "at login; use install --boot to continue after logout"}`);
10027
- if (!(process.env.PATH ?? "").split(":").includes((0, import_node_path20.resolve)(alias, ".."))) console.log(`Add ${(0, import_node_path20.resolve)(alias, "..")} to PATH, or use the command path above.`);
10279
+ if (!(process.env.PATH ?? "").split(":").includes((0, import_node_path21.resolve)(alias, ".."))) console.log(`Add ${(0, import_node_path21.resolve)(alias, "..")} to PATH, or use the command path above.`);
10028
10280
  return 0;
10029
10281
  }
10030
10282
  if (command === "doctor") {
@@ -10040,7 +10292,7 @@ Services: ${components2.map((target) => unitName(dir, target)).join(", ")}`);
10040
10292
  const config = readSetup(dir);
10041
10293
  if (!config) {
10042
10294
  if (command === "status") {
10043
- console.log(`Rigscope ${JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path20.join)(ROOT, "package.json"), "utf8")).version}
10295
+ console.log(`Rigscope ${JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path21.join)(ROOT, "package.json"), "utf8")).version}
10044
10296
  No user installation.
10045
10297
  Install background monitoring: rigscope install --boot
10046
10298
  Connect to a hub: rigscope install --role collector --boot
@@ -10061,25 +10313,25 @@ ${bold("Components")}:`);
10061
10313
  console.log(` ${bold(label2(target))}: ${componentEnabled(config, target) ? "enabled" : "disabled"}, ${colorize(state2, service.active ? "green" : "gray")}, startup ${service.enabled ? "on" : "off"}${service.installed ? "" : " (not installed)"}`);
10062
10314
  if (service.active && service.execMainPid) console.log(` PID ${service.execMainPid}`);
10063
10315
  }
10064
- console.log(`Configuration: ${(0, import_node_path20.join)(dir, "config.json")}
10316
+ console.log(`Configuration: ${(0, import_node_path21.join)(dir, "config.json")}
10065
10317
  Startup: ${!startup.enabled ? "manual" : startup.linger ? "at boot; continues after logout" : "at login only"}
10066
- CLI version: ${JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path20.join)(ROOT, "package.json"), "utf8")).version}`);
10067
- if ((0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime"))) {
10318
+ CLI version: ${JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path21.join)(ROOT, "package.json"), "utf8")).version}`);
10319
+ if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) {
10068
10320
  try {
10069
- console.log(`Runtime: rigscope ${runtimeVersion((0, import_node_path20.join)(dir, "runtime"))}`);
10321
+ console.log(`Runtime: rigscope ${runtimeVersion((0, import_node_path21.join)(dir, "runtime"))}`);
10070
10322
  } catch {
10071
10323
  console.log("Runtime: invalid (run rigscope doctor)");
10072
10324
  }
10073
10325
  }
10074
- if ((0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime-previous"))) {
10326
+ if ((0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime-previous"))) {
10075
10327
  try {
10076
- console.log(`Previous runtime: rigscope ${runtimeVersion((0, import_node_path20.join)(dir, "runtime-previous"))}`);
10328
+ console.log(`Previous runtime: rigscope ${runtimeVersion((0, import_node_path21.join)(dir, "runtime-previous"))}`);
10077
10329
  } catch {
10078
10330
  console.log("Previous runtime: invalid");
10079
10331
  }
10080
10332
  }
10081
10333
  const releaseState = readRuntimeState(dir);
10082
- const paired = releaseState ? Object.values(releaseState.backups).filter((record) => (0, import_node_fs19.existsSync)(record.path)) : [];
10334
+ const paired = releaseState ? Object.values(releaseState.backups).filter((record) => (0, import_node_fs20.existsSync)(record.path)) : [];
10083
10335
  if (paired.length > 0) console.log(`Paired database backups: ${paired.length}`);
10084
10336
  const hubConfigured2 = config.users.length > 0;
10085
10337
  if (hubConfigured2) console.log(`Hub: ${config.origin ?? `http://127.0.0.1:${config.port}`}`);
@@ -10088,8 +10340,8 @@ CLI version: ${JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_pat
10088
10340
  console.log(`Health: ${health.ok ? "ok" : health.error}
10089
10341
  Running version: ${health.body?.version ?? "unavailable"}`);
10090
10342
  }
10091
- const state = (0, import_node_path20.join)(dir, "collector", "state.json");
10092
- if ((0, import_node_fs19.existsSync)(state)) {
10343
+ const state = (0, import_node_path21.join)(dir, "collector", "state.json");
10344
+ if ((0, import_node_fs20.existsSync)(state)) {
10093
10345
  const saved = JSON.parse(readPrivate(state));
10094
10346
  console.log(`Destinations: ${saved.destinations.length}/8${saved.destinations.length === 0 ? " (awaiting connection)" : ""}`);
10095
10347
  for (const destination of saved.destinations) console.log(` ${destination.url}`);
@@ -10139,9 +10391,9 @@ Running version: ${health.body?.version ?? "unavailable"}`);
10139
10391
  return 0;
10140
10392
  }
10141
10393
  if (command === "upgrade") {
10142
- if (!(0, import_node_fs19.existsSync)((0, import_node_path20.join)(dir, "runtime"))) throw new Error("Install a managed runtime before upgrading.");
10394
+ if (!(0, import_node_fs20.existsSync)((0, import_node_path21.join)(dir, "runtime"))) throw new Error("Install a managed runtime before upgrading.");
10143
10395
  console.log("Staging upgrade\u2026");
10144
- const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path20.resolve)(values.from) : values.from : "rigscope@latest";
10396
+ const source = values.from ? /^[./]/.test(values.from) ? (0, import_node_path21.resolve)(values.from) : values.from : "rigscope@latest";
10145
10397
  const report = await upgradeInstallation({
10146
10398
  root: ROOT,
10147
10399
  dir,
@@ -10153,13 +10405,14 @@ Running version: ${health.body?.version ?? "unavailable"}`);
10153
10405
  if (report.schemaVersion !== null) console.log(`Database schema: ${report.schemaVersion}`);
10154
10406
  if (report.verification.health) console.log(`Health: ${report.verification.health.attempts} probe(s) in ${report.verification.health.elapsedMs}ms`);
10155
10407
  else console.log("Health: skipped because the service was inactive; start it explicitly.");
10408
+ printMachineDataOutcome2(report.machineHistory);
10156
10409
  return 0;
10157
10410
  }
10158
10411
  if (command === "rollback") {
10159
10412
  console.log("Rolling back\u2026");
10160
10413
  const report = await rollbackInstallation({
10161
10414
  dir,
10162
- backup: values.backup ? (0, import_node_path20.resolve)(values.backup) : void 0,
10415
+ backup: values.backup ? (0, import_node_path21.resolve)(values.backup) : void 0,
10163
10416
  healthDeadlineMs: healthDeadline(values.timeout)
10164
10417
  });
10165
10418
  printSuccess(`Rolled back: rigscope ${report.version} (previous ${report.previousVersion}).`);
@@ -10177,7 +10430,7 @@ Running version: ${health.body?.version ?? "unavailable"}`);
10177
10430
  if (!componentEnabled(config, "hub")) throw new Error("This installation has no hub component.");
10178
10431
  const password = recoveryPassword;
10179
10432
  const report = await recoverAdminPassword({
10180
- database: (0, import_node_path20.join)(dir, "hub", "telemetry.sqlite"),
10433
+ database: (0, import_node_path21.join)(dir, "hub", "telemetry.sqlite"),
10181
10434
  username: values.user ?? "owner",
10182
10435
  password,
10183
10436
  enable: values.enable === true