@camstack/server 1.2.690 → 1.2.692

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.692] - 2026-10-29
11
+
12
+ ### Changed
13
+
14
+ - A node inside the desktop app reports the app version and update state to the hub, and the hub can trigger install and restart.
15
+
16
+ ## [1.2.691] - 2026-10-29
17
+
18
+ ### Changed
19
+
20
+ - An unpaired agent now shows its real memory on its own page instead of unknown.
21
+
10
22
  ## [1.2.690] - 2026-10-29
11
23
 
12
24
  ### Changed
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveStatusMetrics = resolveStatusMetrics;
4
+ /**
5
+ * The metrics source `$agent.status` reads (and so the agent's own local page).
6
+ *
7
+ * A PAIRED agent boots the `metrics-provider` addon, so the registry answers. An
8
+ * UNPAIRED agent boots no addon at all (agent-boot-mode.ts), the registry has no
9
+ * provider, and the page read memory as unknown although the host reader works. The
10
+ * fallback is the SAME native reader the addon registers - never a second formula -
11
+ * and it is asked only when the registry has nothing.
12
+ */
13
+ function resolveStatusMetrics(fromRegistry, fallback) {
14
+ return () => fromRegistry() ?? fallback();
15
+ }
@@ -59,6 +59,7 @@ const agent_node_certificates_js_1 = require("./agent-node-certificates.js");
59
59
  const agent_reconnect_js_1 = require("./agent-reconnect.js");
60
60
  const serial_queue_js_1 = require("./serial-queue.js");
61
61
  const agent_boot_mode_js_1 = require("./agent-boot-mode.js");
62
+ const agent_status_metrics_js_1 = require("./agent-status-metrics.js");
62
63
  const agent_self_update_js_1 = require("./agent-self-update.js");
63
64
  const update_check_scheduler_js_1 = require("../core/updates/update-check-scheduler.js");
64
65
  const agent_infra_capabilities_js_1 = require("./agent-infra-capabilities.js");
@@ -437,6 +438,7 @@ async function startAgent(configPath) {
437
438
  withTags: () => consoleLogger,
438
439
  };
439
440
  const capabilityRegistry = new system_1.CapabilityRegistry(consoleLogger);
441
+ let unpairedMetrics = null;
440
442
  // Declare all capabilities the agent uses — required before registerProvider()
441
443
  const agentCapabilities = [
442
444
  types_2.storageCapability,
@@ -553,7 +555,17 @@ async function startAgent(configPath) {
553
555
  // Resolve the current metrics-provider cap lazily from the registry.
554
556
  // The cap is registered during bootCoreAddons but may not exist in test
555
557
  // scenarios — `null` is a documented fallback for both.
556
- getMetricsProvider: () => capabilityRegistry.getSingleton('metrics-provider'),
558
+ // An UNPAIRED agent boots no addon, so the registry has no provider: its own page
559
+ // reads the same native reader the addon would register (see agent-status-metrics.ts).
560
+ getMetricsProvider: (0, agent_status_metrics_js_1.resolveStatusMetrics)(() => capabilityRegistry.getSingleton('metrics-provider'), () => {
561
+ if ((0, agent_boot_mode_js_1.decideAgentBootMode)({ paired: (0, agent_pairing_store_js_1.isAgentPaired)(config.configPath) }) === 'full')
562
+ return null;
563
+ if (unpairedMetrics === null) {
564
+ unpairedMetrics = new system_1.NativeMetricsProvider();
565
+ unpairedMetrics.startSampling(5000);
566
+ }
567
+ return unpairedMetrics;
568
+ }),
557
569
  agentVersion: readAgentVersion(),
558
570
  // Drives `$agent.reload` — re-runs the same discovery pass the bootstrap
559
571
  // does at startup, picking up tarballs just landed via `$agent.deploy`.
@@ -20,6 +20,7 @@ function buildServerManagementProvider(service, dataDir) {
20
20
  getServerPackageStatus: () => service.getServerPackageStatus(),
21
21
  checkServerUpdate: () => service.checkServerUpdate(),
22
22
  applyServerUpdate: (input) => service.applyServerUpdate(input),
23
+ installDesktopUpdate: () => Promise.resolve(service.installDesktopUpdate()),
23
24
  rollbackServerUpdate: () => service.rollbackServerUpdate(),
24
25
  restartServer: () => Promise.resolve(service.restartNode()),
25
26
  ...buildLaunchOverrideMethods(dataDir),
@@ -11033,6 +11033,13 @@ function createCapRouter_serverManagement(getProvider, createRemoteProxy) {
11033
11033
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
11034
11034
  return p.applyServerUpdate(methodInput);
11035
11035
  }),
11036
+ installDesktopUpdate: trpc_middleware_js_1.adminProcedure
11037
+ .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
11038
+ .output(types_126.serverManagementCapability.methods.installDesktopUpdate.output)
11039
+ .mutation(async ({ input, ctx }) => {
11040
+ const p = resolveProvider('server-management', input?.nodeId, () => getProvider(ctx), createRemoteProxy);
11041
+ return p.installDesktopUpdate();
11042
+ }),
11036
11043
  rollbackServerUpdate: trpc_middleware_js_1.adminProcedure
11037
11044
  .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
11038
11045
  .output(types_126.serverManagementCapability.methods.rollbackServerUpdate.output)
@@ -74,6 +74,10 @@ var require_dist = __commonJS({
74
74
  var src_exports = {};
75
75
  __export2(src_exports, {
76
76
  CURRENT_DIRNAME: /* @__PURE__ */ __name(() => CURRENT_DIRNAME, "CURRENT_DIRNAME"),
77
+ DESKTOP_APP_STATE_FILE: /* @__PURE__ */ __name(() => DESKTOP_APP_STATE_FILE, "DESKTOP_APP_STATE_FILE"),
78
+ DESKTOP_APP_STATE_STALE_MS: /* @__PURE__ */ __name(() => DESKTOP_APP_STATE_STALE_MS, "DESKTOP_APP_STATE_STALE_MS"),
79
+ DESKTOP_INSTALL_REQUEST_FILE: /* @__PURE__ */ __name(() => DESKTOP_INSTALL_REQUEST_FILE, "DESKTOP_INSTALL_REQUEST_FILE"),
80
+ DESKTOP_INSTALL_REQUEST_MAX_AGE_MS: /* @__PURE__ */ __name(() => DESKTOP_INSTALL_REQUEST_MAX_AGE_MS, "DESKTOP_INSTALL_REQUEST_MAX_AGE_MS"),
77
81
  DEV_UPLOADS_DIRNAME: /* @__PURE__ */ __name(() => DEV_UPLOADS_DIRNAME, "DEV_UPLOADS_DIRNAME"),
78
82
  DEV_UPLOADS_KEEP_COUNT: /* @__PURE__ */ __name(() => DEV_UPLOADS_KEEP_COUNT, "DEV_UPLOADS_KEEP_COUNT"),
79
83
  DEV_UPLOAD_MANIFEST_FILE: /* @__PURE__ */ __name(() => DEV_UPLOAD_MANIFEST_FILE, "DEV_UPLOAD_MANIFEST_FILE"),
@@ -95,8 +99,11 @@ var require_dist = __commonJS({
95
99
  clearPendingRootSwap: /* @__PURE__ */ __name(() => clearPendingRootSwap, "clearPendingRootSwap"),
96
100
  clearRestartIntentMarker: /* @__PURE__ */ __name(() => clearRestartIntentMarker, "clearRestartIntentMarker"),
97
101
  compareSemver: /* @__PURE__ */ __name(() => compareSemver, "compareSemver"),
102
+ consumeDesktopInstallRequest: /* @__PURE__ */ __name(() => consumeDesktopInstallRequest, "consumeDesktopInstallRequest"),
98
103
  currentDir: /* @__PURE__ */ __name(() => currentDir, "currentDir"),
99
104
  currentEntryPath: /* @__PURE__ */ __name(() => currentEntryPath, "currentEntryPath"),
105
+ desktopAppStatePath: /* @__PURE__ */ __name(() => desktopAppStatePath, "desktopAppStatePath"),
106
+ desktopInstallRequestPath: /* @__PURE__ */ __name(() => desktopInstallRequestPath, "desktopInstallRequestPath"),
100
107
  detectWorkspaceRoot: /* @__PURE__ */ __name(() => detectWorkspaceRoot, "detectWorkspaceRoot"),
101
108
  detectWrapperIdentity: /* @__PURE__ */ __name(() => detectWrapperIdentity, "detectWrapperIdentity"),
102
109
  devChannelEpoch: /* @__PURE__ */ __name(() => devChannelEpoch, "devChannelEpoch"),
@@ -106,6 +113,8 @@ var require_dist = __commonJS({
106
113
  emptyServerRootState: /* @__PURE__ */ __name(() => emptyServerRootState, "emptyServerRootState"),
107
114
  findMissingNativePrebuilds: /* @__PURE__ */ __name(() => findMissingNativePrebuilds, "findMissingNativePrebuilds"),
108
115
  findUnappliedClosurePatches: /* @__PURE__ */ __name(() => findUnappliedClosurePatches, "findUnappliedClosurePatches"),
116
+ isDesktopAppStateFile: /* @__PURE__ */ __name(() => isDesktopAppStateFile, "isDesktopAppStateFile"),
117
+ isDesktopInstallRequestFile: /* @__PURE__ */ __name(() => isDesktopInstallRequestFile, "isDesktopInstallRequestFile"),
109
118
  isDevChannelVersion: /* @__PURE__ */ __name(() => isDevChannelVersion, "isDevChannelVersion"),
110
119
  isHostExternal: /* @__PURE__ */ __name(() => isHostExternal, "isHostExternal"),
111
120
  isServerRootState: /* @__PURE__ */ __name(() => isServerRootState, "isServerRootState"),
@@ -114,6 +123,7 @@ var require_dist = __commonJS({
114
123
  minNodeMajorOf: /* @__PURE__ */ __name(() => minNodeMajorOf, "minNodeMajorOf"),
115
124
  pendingRootSwapPath: /* @__PURE__ */ __name(() => pendingRootSwapPath, "pendingRootSwapPath"),
116
125
  planBoot: /* @__PURE__ */ __name(() => planBoot, "planBoot"),
126
+ readDesktopAppState: /* @__PURE__ */ __name(() => readDesktopAppState, "readDesktopAppState"),
117
127
  readDevUploadManifest: /* @__PURE__ */ __name(() => readDevUploadManifest, "readDevUploadManifest"),
118
128
  readPendingRootSwap: /* @__PURE__ */ __name(() => readPendingRootSwap, "readPendingRootSwap"),
119
129
  readRestartIntentMarker: /* @__PURE__ */ __name(() => readRestartIntentMarker, "readRestartIntentMarker"),
@@ -132,6 +142,8 @@ var require_dist = __commonJS({
132
142
  validateVersionDir: /* @__PURE__ */ __name(() => validateVersionDir, "validateVersionDir"),
133
143
  versionDir: /* @__PURE__ */ __name(() => versionDir, "versionDir"),
134
144
  versionsDir: /* @__PURE__ */ __name(() => versionsDir, "versionsDir"),
145
+ writeDesktopAppState: /* @__PURE__ */ __name(() => writeDesktopAppState, "writeDesktopAppState"),
146
+ writeDesktopInstallRequest: /* @__PURE__ */ __name(() => writeDesktopInstallRequest, "writeDesktopInstallRequest"),
135
147
  writeDevUploadManifest: /* @__PURE__ */ __name(() => writeDevUploadManifest, "writeDevUploadManifest"),
136
148
  writePendingRootSwap: /* @__PURE__ */ __name(() => writePendingRootSwap, "writePendingRootSwap"),
137
149
  writeRestartIntentMarker: /* @__PURE__ */ __name(() => writeRestartIntentMarker, "writeRestartIntentMarker"),
@@ -373,6 +385,83 @@ var require_dist = __commonJS({
373
385
  __name(validateVersionDir, "validateVersionDir");
374
386
  var fs3 = __toESM2(require("fs"));
375
387
  var path3 = __toESM2(require("path"));
388
+ var DESKTOP_APP_STATE_FILE = "desktop-app-state.json";
389
+ var DESKTOP_INSTALL_REQUEST_FILE = "desktop-install-request.json";
390
+ var DESKTOP_APP_STATE_STALE_MS = 15 * 6e4;
391
+ var DESKTOP_INSTALL_REQUEST_MAX_AGE_MS = 6e4;
392
+ function desktopAppStatePath(rootDir) {
393
+ return path3.join(rootDir, DESKTOP_APP_STATE_FILE);
394
+ }
395
+ __name(desktopAppStatePath, "desktopAppStatePath");
396
+ function desktopInstallRequestPath(rootDir) {
397
+ return path3.join(rootDir, DESKTOP_INSTALL_REQUEST_FILE);
398
+ }
399
+ __name(desktopInstallRequestPath, "desktopInstallRequestPath");
400
+ function isRecord(v) {
401
+ return typeof v === "object" && v !== null;
402
+ }
403
+ __name(isRecord, "isRecord");
404
+ function isNullableString2(v) {
405
+ return v === null || typeof v === "string";
406
+ }
407
+ __name(isNullableString2, "isNullableString2");
408
+ function isDesktopAppStateFile(v) {
409
+ if (!isRecord(v)) return false;
410
+ return typeof v["appVersion"] === "string" && typeof v["available"] === "boolean" && typeof v["downloaded"] === "boolean" && isNullableString2(v["version"]) && typeof v["checking"] === "boolean" && isNullableString2(v["error"]) && typeof v["updatedAtMs"] === "number";
411
+ }
412
+ __name(isDesktopAppStateFile, "isDesktopAppStateFile");
413
+ function isDesktopInstallRequestFile(v) {
414
+ if (!isRecord(v)) return false;
415
+ return typeof v["requestedAtMs"] === "number" && typeof v["nonce"] === "string";
416
+ }
417
+ __name(isDesktopInstallRequestFile, "isDesktopInstallRequestFile");
418
+ function writeJsonAtomic(target, value) {
419
+ fs3.mkdirSync(path3.dirname(target), {
420
+ recursive: true
421
+ });
422
+ const tmp = `${target}.tmp`;
423
+ fs3.writeFileSync(tmp, JSON.stringify(value, null, 2), "utf-8");
424
+ fs3.renameSync(tmp, target);
425
+ }
426
+ __name(writeJsonAtomic, "writeJsonAtomic");
427
+ function writeDesktopAppState(rootDir, state) {
428
+ writeJsonAtomic(desktopAppStatePath(rootDir), state);
429
+ }
430
+ __name(writeDesktopAppState, "writeDesktopAppState");
431
+ function readDesktopAppState(rootDir) {
432
+ try {
433
+ const raw = JSON.parse(fs3.readFileSync(desktopAppStatePath(rootDir), "utf-8"));
434
+ return isDesktopAppStateFile(raw) ? raw : null;
435
+ } catch {
436
+ return null;
437
+ }
438
+ }
439
+ __name(readDesktopAppState, "readDesktopAppState");
440
+ function writeDesktopInstallRequest(rootDir, request) {
441
+ writeJsonAtomic(desktopInstallRequestPath(rootDir), request);
442
+ }
443
+ __name(writeDesktopInstallRequest, "writeDesktopInstallRequest");
444
+ function consumeDesktopInstallRequest(rootDir, nowMs, maxAgeMs = DESKTOP_INSTALL_REQUEST_MAX_AGE_MS) {
445
+ const target = desktopInstallRequestPath(rootDir);
446
+ let parsed = null;
447
+ try {
448
+ const raw = JSON.parse(fs3.readFileSync(target, "utf-8"));
449
+ if (isDesktopInstallRequestFile(raw)) parsed = raw;
450
+ } catch {
451
+ }
452
+ try {
453
+ fs3.rmSync(target, {
454
+ force: true
455
+ });
456
+ } catch {
457
+ }
458
+ if (parsed === null) return null;
459
+ if (nowMs - parsed.requestedAtMs > maxAgeMs) return null;
460
+ return parsed;
461
+ }
462
+ __name(consumeDesktopInstallRequest, "consumeDesktopInstallRequest");
463
+ var fs4 = __toESM2(require("fs"));
464
+ var path4 = __toESM2(require("path"));
376
465
  function parse(version) {
377
466
  const dashIdx = version.indexOf("-");
378
467
  const base = dashIdx === -1 ? version : version.slice(0, dashIdx);
@@ -412,7 +501,7 @@ var require_dist = __commonJS({
412
501
  ".framework-swap-confirm.json"
413
502
  ];
414
503
  function currentDir(rootDir) {
415
- return path3.join(rootDir, CURRENT_DIRNAME);
504
+ return path4.join(rootDir, CURRENT_DIRNAME);
416
505
  }
417
506
  __name(currentDir, "currentDir");
418
507
  function currentEntryPath(rootDir, spec) {
@@ -420,11 +509,11 @@ var require_dist = __commonJS({
420
509
  }
421
510
  __name(currentEntryPath, "currentEntryPath");
422
511
  function stagingDirPath(rootDir, target, pid, now) {
423
- return path3.join(rootDir, `.staging-${target}-${pid}-${now}`);
512
+ return path4.join(rootDir, `.staging-${target}-${pid}-${now}`);
424
513
  }
425
514
  __name(stagingDirPath, "stagingDirPath");
426
515
  function pendingRootSwapPath(rootDir) {
427
- return path3.join(rootDir, PENDING_ROOT_SWAP_FILE);
516
+ return path4.join(rootDir, PENDING_ROOT_SWAP_FILE);
428
517
  }
429
518
  __name(pendingRootSwapPath, "pendingRootSwapPath");
430
519
  function isPendingRootSwap(v) {
@@ -435,7 +524,7 @@ var require_dist = __commonJS({
435
524
  __name(isPendingRootSwap, "isPendingRootSwap");
436
525
  function readPendingRootSwap(rootDir) {
437
526
  try {
438
- const raw = JSON.parse(fs3.readFileSync(pendingRootSwapPath(rootDir), "utf-8"));
527
+ const raw = JSON.parse(fs4.readFileSync(pendingRootSwapPath(rootDir), "utf-8"));
439
528
  return isPendingRootSwap(raw) ? raw : null;
440
529
  } catch {
441
530
  return null;
@@ -443,18 +532,18 @@ var require_dist = __commonJS({
443
532
  }
444
533
  __name(readPendingRootSwap, "readPendingRootSwap");
445
534
  function writePendingRootSwap(rootDir, marker) {
446
- fs3.mkdirSync(rootDir, {
535
+ fs4.mkdirSync(rootDir, {
447
536
  recursive: true
448
537
  });
449
538
  const target = pendingRootSwapPath(rootDir);
450
539
  const tmp = `${target}.tmp`;
451
- fs3.writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
452
- fs3.renameSync(tmp, target);
540
+ fs4.writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
541
+ fs4.renameSync(tmp, target);
453
542
  }
454
543
  __name(writePendingRootSwap, "writePendingRootSwap");
455
544
  function clearPendingRootSwap(rootDir) {
456
545
  try {
457
- fs3.rmSync(pendingRootSwapPath(rootDir), {
546
+ fs4.rmSync(pendingRootSwapPath(rootDir), {
458
547
  force: true
459
548
  });
460
549
  } catch {
@@ -482,7 +571,7 @@ var require_dist = __commonJS({
482
571
  function hasDotNode(dir, maxDepth) {
483
572
  let entries;
484
573
  try {
485
- entries = fs3.readdirSync(dir, {
574
+ entries = fs4.readdirSync(dir, {
486
575
  withFileTypes: true
487
576
  });
488
577
  } catch {
@@ -493,19 +582,19 @@ var require_dist = __commonJS({
493
582
  }
494
583
  if (maxDepth <= 0) return false;
495
584
  for (const entry of entries) {
496
- if (entry.isDirectory() && hasDotNode(path3.join(dir, entry.name), maxDepth - 1)) return true;
585
+ if (entry.isDirectory() && hasDotNode(path4.join(dir, entry.name), maxDepth - 1)) return true;
497
586
  }
498
587
  return false;
499
588
  }
500
589
  __name(hasDotNode, "hasDotNode");
501
590
  function findMissingNativePrebuilds(closureDir) {
502
- const nm = path3.join(closureDir, "node_modules");
591
+ const nm = path4.join(closureDir, "node_modules");
503
592
  const missing = [];
504
593
  for (const pkg of REQUIRED_NATIVE_PACKAGES) {
505
594
  const searchDirs = NATIVE_SEARCH_DIRS[pkg] ?? [
506
595
  pkg
507
596
  ];
508
- const found = searchDirs.some((rel) => hasDotNode(path3.join(nm, ...rel.split("/")), 4));
597
+ const found = searchDirs.some((rel) => hasDotNode(path4.join(nm, ...rel.split("/")), 4));
509
598
  if (!found) missing.push(pkg);
510
599
  }
511
600
  return missing;
@@ -521,37 +610,37 @@ var require_dist = __commonJS({
521
610
  var CLOSURE_PATCH_MANIFEST = "patch-reach.json";
522
611
  function fileContains(file, marker) {
523
612
  try {
524
- return fs3.readFileSync(file, "utf-8").includes(marker);
613
+ return fs4.readFileSync(file, "utf-8").includes(marker);
525
614
  } catch {
526
615
  return false;
527
616
  }
528
617
  }
529
618
  __name(fileContains, "fileContains");
530
619
  function findUnappliedClosurePatches(closureDir) {
531
- const payloadDir = path3.join(closureDir, ...CLOSURE_PATCH_PAYLOAD);
620
+ const payloadDir = path4.join(closureDir, ...CLOSURE_PATCH_PAYLOAD);
532
621
  let manifest;
533
622
  try {
534
- const raw = JSON.parse(fs3.readFileSync(path3.join(payloadDir, CLOSURE_PATCH_MANIFEST), "utf-8"));
623
+ const raw = JSON.parse(fs4.readFileSync(path4.join(payloadDir, CLOSURE_PATCH_MANIFEST), "utf-8"));
535
624
  if (typeof raw !== "object" || raw === null) return [];
536
625
  manifest = raw;
537
626
  } catch {
538
627
  return [];
539
628
  }
540
629
  if (!Array.isArray(manifest.patches)) return [];
541
- const nm = path3.join(closureDir, "node_modules");
630
+ const nm = path4.join(closureDir, "node_modules");
542
631
  const missing = [];
543
632
  for (const raw of manifest.patches) {
544
633
  if (raw.reach !== "closure-postinstall") continue;
545
634
  const pkg = raw.package;
546
635
  const markers = raw.markers;
547
636
  if (typeof pkg !== "string" || typeof markers !== "object" || markers === null) continue;
548
- const pkgDir = path3.join(nm, pkg);
549
- if (!fs3.existsSync(pkgDir)) {
637
+ const pkgDir = path4.join(nm, pkg);
638
+ if (!fs4.existsSync(pkgDir)) {
550
639
  continue;
551
640
  }
552
641
  for (const [rel, list] of Object.entries(markers)) {
553
642
  if (!Array.isArray(list)) continue;
554
- const target = path3.join(pkgDir, ...rel.split("/"));
643
+ const target = path4.join(pkgDir, ...rel.split("/"));
555
644
  for (const marker of list) {
556
645
  if (typeof marker !== "string") continue;
557
646
  if (!fileContains(target, marker)) {
@@ -565,7 +654,7 @@ var require_dist = __commonJS({
565
654
  __name(findUnappliedClosurePatches, "findUnappliedClosurePatches");
566
655
  function rmrf(target) {
567
656
  try {
568
- fs3.rmSync(target, {
657
+ fs4.rmSync(target, {
569
658
  recursive: true,
570
659
  force: true
571
660
  });
@@ -588,7 +677,7 @@ var require_dist = __commonJS({
588
677
  const dest = currentDir(rootDir);
589
678
  const invalid = validateClosureDir(staging, nodeMajor, spec, marker.version);
590
679
  if (invalid !== null) {
591
- if (!fs3.existsSync(staging) && validateClosureDir(dest, nodeMajor, spec, marker.version) === null) {
680
+ if (!fs4.existsSync(staging) && validateClosureDir(dest, nodeMajor, spec, marker.version) === null) {
592
681
  clearPendingRootSwap(rootDir);
593
682
  log(`[single-copy] pending swap ${marker.version} already applied \u2014 cleared marker`);
594
683
  return {
@@ -619,16 +708,16 @@ var require_dist = __commonJS({
619
708
  }
620
709
  let trash = null;
621
710
  try {
622
- if (fs3.existsSync(dest)) {
623
- trash = path3.join(rootDir, `.trash-${now()}-${process.pid}`);
624
- fs3.renameSync(dest, trash);
711
+ if (fs4.existsSync(dest)) {
712
+ trash = path4.join(rootDir, `.trash-${now()}-${process.pid}`);
713
+ fs4.renameSync(dest, trash);
625
714
  }
626
715
  try {
627
- fs3.renameSync(staging, dest);
716
+ fs4.renameSync(staging, dest);
628
717
  } catch (err) {
629
- if (trash !== null && !fs3.existsSync(dest)) {
718
+ if (trash !== null && !fs4.existsSync(dest)) {
630
719
  try {
631
- fs3.renameSync(trash, dest);
720
+ fs4.renameSync(trash, dest);
632
721
  } catch {
633
722
  }
634
723
  }
@@ -654,7 +743,7 @@ var require_dist = __commonJS({
654
743
  __name(applyPendingRootSwap, "applyPendingRootSwap");
655
744
  function readClosureVersion(closureDir, spec) {
656
745
  try {
657
- const raw = JSON.parse(fs3.readFileSync(path3.join(rootPackageDir2(closureDir, spec), "package.json"), "utf-8"));
746
+ const raw = JSON.parse(fs4.readFileSync(path4.join(rootPackageDir2(closureDir, spec), "package.json"), "utf-8"));
658
747
  if (typeof raw === "object" && raw !== null) {
659
748
  const version = raw["version"];
660
749
  if (typeof version === "string") return version;
@@ -674,7 +763,7 @@ var require_dist = __commonJS({
674
763
  const legacyState = readServerRootState(rootDir);
675
764
  const pendingVersion = legacyState?.pendingBoot?.version ?? null;
676
765
  const pendingAdoptable = pendingVersion !== null && isAdoptablePendingClosure(rootDir, pendingVersion, nodeMajor, spec);
677
- const currentValid = fs3.existsSync(dest) && validateClosureDir(dest, nodeMajor, spec) === null;
766
+ const currentValid = fs4.existsSync(dest) && validateClosureDir(dest, nodeMajor, spec) === null;
678
767
  if (currentValid) {
679
768
  const currentVersion = readClosureVersion(dest, spec);
680
769
  const pendingSupersedes = pendingAdoptable && pendingVersion !== null && (currentVersion === null || compareSemver(pendingVersion, currentVersion) > 0);
@@ -699,7 +788,7 @@ var require_dist = __commonJS({
699
788
  }
700
789
  }
701
790
  try {
702
- for (const entry of fs3.readdirSync(versionsDir(rootDir))) {
791
+ for (const entry of fs4.readdirSync(versionsDir(rootDir))) {
703
792
  if (!entry.startsWith(".") && !candidates.includes(entry)) candidates.push(entry);
704
793
  }
705
794
  } catch {
@@ -712,16 +801,16 @@ var require_dist = __commonJS({
712
801
  reason: "no valid legacy versions/<X> to adopt"
713
802
  };
714
803
  }
715
- if (fs3.existsSync(dest)) {
716
- const aside = path3.join(rootDir, `.trash-${now()}-${process.pid}-stale-current`);
804
+ if (fs4.existsSync(dest)) {
805
+ const aside = path4.join(rootDir, `.trash-${now()}-${process.pid}-stale-current`);
717
806
  try {
718
- fs3.renameSync(dest, aside);
807
+ fs4.renameSync(dest, aside);
719
808
  } catch {
720
809
  rmrf(dest);
721
810
  }
722
811
  }
723
812
  try {
724
- fs3.renameSync(versionDir(rootDir, source), dest);
813
+ fs4.renameSync(versionDir(rootDir, source), dest);
725
814
  } catch (err) {
726
815
  log(`[single-copy] migration rename of versions/${source} failed (${errMsg(err)})`);
727
816
  return {
@@ -732,8 +821,8 @@ var require_dist = __commonJS({
732
821
  }
733
822
  rmrf(versionsDir(rootDir));
734
823
  rmrf(stateFilePath(rootDir));
735
- const dataDir = path3.dirname(rootDir);
736
- for (const marker of LEGACY_FRAMEWORK_MARKERS) rmrf(path3.join(dataDir, marker));
824
+ const dataDir = path4.dirname(rootDir);
825
+ for (const marker of LEGACY_FRAMEWORK_MARKERS) rmrf(path4.join(dataDir, marker));
737
826
  log(`[single-copy] migrated legacy versions/${source} \u2192 current`);
738
827
  return {
739
828
  migrated: true,
@@ -745,15 +834,15 @@ var require_dist = __commonJS({
745
834
  function sweepTransientRootDirs(rootDir, now, staleMs) {
746
835
  let entries;
747
836
  try {
748
- entries = fs3.readdirSync(rootDir);
837
+ entries = fs4.readdirSync(rootDir);
749
838
  } catch {
750
839
  return;
751
840
  }
752
841
  for (const entry of entries) {
753
842
  if (!entry.startsWith(".staging-") && !entry.startsWith(".trash-")) continue;
754
- const full = path3.join(rootDir, entry);
843
+ const full = path4.join(rootDir, entry);
755
844
  try {
756
- if (now - fs3.statSync(full).mtimeMs < staleMs) continue;
845
+ if (now - fs4.statSync(full).mtimeMs < staleMs) continue;
757
846
  } catch {
758
847
  continue;
759
848
  }
@@ -937,27 +1026,27 @@ var require_dist = __commonJS({
937
1026
  };
938
1027
  }
939
1028
  __name(detectWrapperIdentity, "detectWrapperIdentity");
940
- var fs4 = __toESM2(require("fs"));
941
- var path4 = __toESM2(require("path"));
1029
+ var fs5 = __toESM2(require("fs"));
1030
+ var path5 = __toESM2(require("path"));
942
1031
  function detectWorkspaceRoot(fromDir) {
943
- let dir = path4.resolve(fromDir);
1032
+ let dir = path5.resolve(fromDir);
944
1033
  for (; ; ) {
945
- const pkgPath = path4.join(dir, "package.json");
1034
+ const pkgPath = path5.join(dir, "package.json");
946
1035
  try {
947
- const raw = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
1036
+ const raw = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
948
1037
  if (typeof raw === "object" && raw !== null && raw["workspaces"] !== void 0) {
949
1038
  return dir;
950
1039
  }
951
1040
  } catch {
952
1041
  }
953
- const parent = path4.dirname(dir);
1042
+ const parent = path5.dirname(dir);
954
1043
  if (parent === dir) return null;
955
1044
  dir = parent;
956
1045
  }
957
1046
  }
958
1047
  __name(detectWorkspaceRoot, "detectWorkspaceRoot");
959
- var fs5 = __toESM2(require("fs"));
960
- var path5 = __toESM2(require("path"));
1048
+ var fs6 = __toESM2(require("fs"));
1049
+ var path6 = __toESM2(require("path"));
961
1050
  var import_node_url = require("url");
962
1051
  var HOST_EXTERNAL_SPECIFIERS = [
963
1052
  "@camstack/system",
@@ -982,7 +1071,7 @@ var require_dist = __commonJS({
982
1071
  console.warn("[starter] module.registerHooks unavailable (Node < 22.15) \u2014 host-external redirect skipped");
983
1072
  return;
984
1073
  }
985
- const anchorURL = (0, import_node_url.pathToFileURL)(path5.join(activeRootDir, "node_modules", "__camstack_starter_anchor__.js")).href;
1074
+ const anchorURL = (0, import_node_url.pathToFileURL)(path6.join(activeRootDir, "node_modules", "__camstack_starter_anchor__.js")).href;
986
1075
  const hooks = {
987
1076
  resolve: /* @__PURE__ */ __name((specifier, context, nextResolve) => {
988
1077
  if (isHostExternal(specifier)) {
@@ -1002,7 +1091,7 @@ var require_dist = __commonJS({
1002
1091
  __name(registerActiveRootResolver, "registerActiveRootResolver");
1003
1092
  function readClosureVersion2(closureDir, spec) {
1004
1093
  try {
1005
- const raw = JSON.parse(fs5.readFileSync(path5.join(rootPackageDir2(closureDir, spec), "package.json"), "utf-8"));
1094
+ const raw = JSON.parse(fs6.readFileSync(path6.join(rootPackageDir2(closureDir, spec), "package.json"), "utf-8"));
1006
1095
  if (typeof raw === "object" && raw !== null) {
1007
1096
  const version = raw["version"];
1008
1097
  if (typeof version === "string") return version;
@@ -1039,7 +1128,7 @@ var require_dist = __commonJS({
1039
1128
  if (migration.migrated) console.log(`[starter] migrated legacy layout \u2192 single copy (${migration.version ?? "?"})`);
1040
1129
  const activeRootDir = currentDir(rootDir);
1041
1130
  const invalid = validateClosureDir(activeRootDir, nodeMajor, options.spec);
1042
- if (invalid !== null && fs5.existsSync(activeRootDir)) {
1131
+ if (invalid !== null && fs6.existsSync(activeRootDir)) {
1043
1132
  console.warn(`[starter] single copy invalid: ${invalid}`);
1044
1133
  }
1045
1134
  const plan = planBoot(invalid === null);
@@ -1060,8 +1149,9 @@ var require_dist = __commonJS({
1060
1149
  }
1061
1150
  __name(runNodeStarter, "runNodeStarter");
1062
1151
  var import_node_child_process = require("child_process");
1063
- var fs6 = __toESM2(require("fs"));
1064
- var path6 = __toESM2(require("path"));
1152
+ var fs7 = __toESM2(require("fs"));
1153
+ var path7 = __toESM2(require("path"));
1154
+ var import_node_crypto = require("crypto");
1065
1155
  var import_node_util = require("util");
1066
1156
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
1067
1157
  function buildNpmRegistryArgs(registry) {
@@ -1101,13 +1191,13 @@ var require_dist = __commonJS({
1101
1191
  function readWrapperProbes() {
1102
1192
  let proc1Cgroup = null;
1103
1193
  try {
1104
- proc1Cgroup = fs6.readFileSync("/proc/1/cgroup", "utf-8");
1194
+ proc1Cgroup = fs7.readFileSync("/proc/1/cgroup", "utf-8");
1105
1195
  } catch {
1106
1196
  proc1Cgroup = null;
1107
1197
  }
1108
1198
  let dockerEnvFileExists = false;
1109
1199
  try {
1110
- dockerEnvFileExists = fs6.existsSync("/.dockerenv");
1200
+ dockerEnvFileExists = fs7.existsSync("/.dockerenv");
1111
1201
  } catch {
1112
1202
  dockerEnvFileExists = false;
1113
1203
  }
@@ -1120,7 +1210,7 @@ var require_dist = __commonJS({
1120
1210
  __name(readWrapperProbes, "readWrapperProbes");
1121
1211
  function readPackageVersion(pkgJsonPath) {
1122
1212
  try {
1123
- const raw = JSON.parse(fs6.readFileSync(pkgJsonPath, "utf-8"));
1213
+ const raw = JSON.parse(fs7.readFileSync(pkgJsonPath, "utf-8"));
1124
1214
  if (typeof raw === "object" && raw !== null) {
1125
1215
  const version = raw["version"];
1126
1216
  if (typeof version === "string") return version;
@@ -1173,7 +1263,7 @@ var require_dist = __commonJS({
1173
1263
  nodeId: options.nodeId ?? "unknown"
1174
1264
  };
1175
1265
  this.restartServerFn = options.restartServer;
1176
- this.dataDir = path6.resolve(options.dataDir);
1266
+ this.dataDir = path7.resolve(options.dataDir);
1177
1267
  this.updatePreflightFn = options.updatePreflight ?? null;
1178
1268
  this.runnerBootCheckFn = options.runnerBootCheck ?? (() => void 0);
1179
1269
  this.execNpm = options.execNpm ?? (async (args, opts) => {
@@ -1228,7 +1318,7 @@ var require_dist = __commonJS({
1228
1318
  */
1229
1319
  installedVersion() {
1230
1320
  if (this.resolveBootMode() !== "data-root") return null;
1231
- return readPackageVersion(path6.join(rootPackageDir2(currentDir(this.rootDir()), this.spec), "package.json"));
1321
+ return readPackageVersion(path7.join(rootPackageDir2(currentDir(this.rootDir()), this.spec), "package.json"));
1232
1322
  }
1233
1323
  /**
1234
1324
  * The three facts a restart question needs, read together so no surface can
@@ -1256,7 +1346,7 @@ var require_dist = __commonJS({
1256
1346
  seedVersion() {
1257
1347
  const seedDir = this.env[this.envNames.seedDir];
1258
1348
  if (seedDir === void 0 || seedDir.length === 0) return null;
1259
- return readPackageVersion(path6.join(seedDir, "package.json"));
1349
+ return readPackageVersion(path7.join(seedDir, "package.json"));
1260
1350
  }
1261
1351
  /**
1262
1352
  * What this node runs INSIDE. Observed where it can be (the container
@@ -1272,6 +1362,30 @@ var require_dist = __commonJS({
1272
1362
  seedVersion: this.seedVersion()
1273
1363
  });
1274
1364
  }
1365
+ /**
1366
+ * The desktop app's own report (ADR-0971), read from the data-dir state
1367
+ * file. Empty when there is no readable file — absent, never a fabricated
1368
+ * "no update". An old file is reported with `stale: true`, not dropped:
1369
+ * the app that stopped writing is itself a fact the operator needs.
1370
+ */
1371
+ desktopAppField() {
1372
+ const state = readDesktopAppState(this.rootDir());
1373
+ if (state === null) return {};
1374
+ return {
1375
+ desktopApp: {
1376
+ version: state.appVersion,
1377
+ update: {
1378
+ available: state.available,
1379
+ downloaded: state.downloaded,
1380
+ version: state.version,
1381
+ checking: state.checking,
1382
+ error: state.error
1383
+ },
1384
+ stateAtMs: state.updatedAtMs,
1385
+ stale: this.now() - state.updatedAtMs > DESKTOP_APP_STATE_STALE_MS
1386
+ }
1387
+ };
1388
+ }
1275
1389
  rootDir() {
1276
1390
  return serverRootDir(this.dataDir);
1277
1391
  }
@@ -1325,6 +1439,7 @@ var require_dist = __commonJS({
1325
1439
  // BEHIND; this says WHAT the shell is, which is the only thing that can
1326
1440
  // turn that verdict into an instruction the operator can act on.
1327
1441
  wrapper: this.wrapperIdentity(),
1442
+ ...this.desktopAppField(),
1328
1443
  // Planned runners against the process service's states (D877); absent
1329
1444
  // until the one-shot boot check has run.
1330
1445
  ...this.runnerBootCheckFn() !== void 0 ? {
@@ -1497,7 +1612,7 @@ var require_dist = __commonJS({
1497
1612
  }
1498
1613
  if (isDevChannelVersion(target)) {
1499
1614
  const uploadsDir = devUploadVersionDir(this.rootDir(), target);
1500
- if (!fs6.existsSync(uploadsDir)) {
1615
+ if (!fs7.existsSync(uploadsDir)) {
1501
1616
  return this.refuseUpdate("dev-uploads-missing", target, `Refused: dev-channel version ${target} has no uploaded tarballs on this node (${uploadsDir} is missing). On the hub: \`camstack deploy-server\`. On an agent: \`camstack deploy-server -n <nodeId>\` (or \`--all\`) so the hub can POST /api/server-upload/propagate first.`);
1502
1617
  }
1503
1618
  }
@@ -1627,11 +1742,11 @@ var require_dist = __commonJS({
1627
1742
  */
1628
1743
  async stageClosure(target) {
1629
1744
  const rootDir = this.rootDir();
1630
- fs6.mkdirSync(rootDir, {
1745
+ fs7.mkdirSync(rootDir, {
1631
1746
  recursive: true
1632
1747
  });
1633
1748
  const stagingDir = stagingDirPath(rootDir, target, process.pid, this.now());
1634
- fs6.mkdirSync(stagingDir, {
1749
+ fs7.mkdirSync(stagingDir, {
1635
1750
  recursive: true
1636
1751
  });
1637
1752
  try {
@@ -1644,8 +1759,8 @@ var require_dist = __commonJS({
1644
1759
  "--no-fund",
1645
1760
  "--loglevel=error"
1646
1761
  ];
1647
- if (fs6.existsSync(devDir)) {
1648
- fs6.writeFileSync(path6.join(stagingDir, "package.json"), JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2), "utf-8");
1762
+ if (fs7.existsSync(devDir)) {
1763
+ fs7.writeFileSync(path7.join(stagingDir, "package.json"), JSON.stringify(this.buildDevUploadsPackageJson(devDir, target), null, 2), "utf-8");
1649
1764
  await this.execNpm([
1650
1765
  ...installArgs,
1651
1766
  ...buildNpmRegistryArgs(registry)
@@ -1654,7 +1769,7 @@ var require_dist = __commonJS({
1654
1769
  timeoutMs: NPM_INSTALL_TIMEOUT_MS
1655
1770
  });
1656
1771
  } else {
1657
- fs6.writeFileSync(path6.join(stagingDir, "package.json"), JSON.stringify({
1772
+ fs7.writeFileSync(path7.join(stagingDir, "package.json"), JSON.stringify({
1658
1773
  name: "camstack-node-root",
1659
1774
  private: true,
1660
1775
  allowScripts: CLOSURE_ALLOW_SCRIPTS
@@ -1669,7 +1784,7 @@ var require_dist = __commonJS({
1669
1784
  });
1670
1785
  }
1671
1786
  const entry = rootEntryPath2(stagingDir, this.spec);
1672
- if (!fs6.existsSync(entry)) {
1787
+ if (!fs7.existsSync(entry)) {
1673
1788
  throw new Error(`staged closure is missing the root entry (${entry})`);
1674
1789
  }
1675
1790
  const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
@@ -1705,7 +1820,7 @@ var require_dist = __commonJS({
1705
1820
  }
1706
1821
  return stagingDir;
1707
1822
  } catch (err) {
1708
- await fs6.promises.rm(stagingDir, {
1823
+ await fs7.promises.rm(stagingDir, {
1709
1824
  recursive: true,
1710
1825
  force: true
1711
1826
  }).catch(() => void 0);
@@ -1732,8 +1847,8 @@ var require_dist = __commonJS({
1732
1847
  throw new Error(`dev-uploads for ${target} do not include the root package ${this.spec.packageName}`);
1733
1848
  }
1734
1849
  const fileRef = /* @__PURE__ */ __name((filename) => {
1735
- const abs = path6.join(devDir, filename);
1736
- if (!fs6.existsSync(abs)) {
1850
+ const abs = path7.join(devDir, filename);
1851
+ if (!fs7.existsSync(abs)) {
1737
1852
  throw new Error(`dev-uploads tarball listed in the manifest is missing: ${abs}`);
1738
1853
  }
1739
1854
  return `file:${abs}`;
@@ -1801,6 +1916,47 @@ var require_dist = __commonJS({
1801
1916
  error: null
1802
1917
  };
1803
1918
  }
1919
+ /**
1920
+ * Ask the desktop app hosting this node to install its downloaded update
1921
+ * (ADR-0971). Writes a request file in the data dir; the app consumes it.
1922
+ * Every refusal names its reason, and the write happens ONLY when the app's
1923
+ * own state says there is something downloaded and that state is fresh —
1924
+ * a request into a dead or empty app would sit on disk until a later launch.
1925
+ */
1926
+ installDesktopUpdate() {
1927
+ const refuse = /* @__PURE__ */ __name((reason) => {
1928
+ this.logger.warn("desktop update install refused", {
1929
+ tags: this.logTags,
1930
+ meta: {
1931
+ reason
1932
+ }
1933
+ });
1934
+ return {
1935
+ accepted: false,
1936
+ reason
1937
+ };
1938
+ }, "refuse");
1939
+ if (this.wrapperIdentity().kind !== "electron") return refuse("not-electron");
1940
+ const desktopApp = this.desktopAppField().desktopApp;
1941
+ if (desktopApp === void 0) return refuse("no-app-state");
1942
+ if (desktopApp.stale) return refuse("app-state-stale");
1943
+ if (!desktopApp.update.downloaded) return refuse("not-downloaded");
1944
+ writeDesktopInstallRequest(this.rootDir(), {
1945
+ requestedAtMs: this.now(),
1946
+ nonce: (0, import_node_crypto.randomUUID)()
1947
+ });
1948
+ this.logger.info("desktop update install requested", {
1949
+ tags: this.logTags,
1950
+ meta: {
1951
+ appVersion: desktopApp.version,
1952
+ updateVersion: desktopApp.update.version
1953
+ }
1954
+ });
1955
+ return {
1956
+ accepted: true,
1957
+ reason: null
1958
+ };
1959
+ }
1804
1960
  restartNode() {
1805
1961
  const runningVersion = this.runningVersion();
1806
1962
  if (this.inFlight !== "idle") {
@@ -1850,15 +2006,15 @@ var require_dist = __commonJS({
1850
2006
  const dir = devUploadsDir(this.rootDir());
1851
2007
  let entries;
1852
2008
  try {
1853
- entries = fs6.readdirSync(dir);
2009
+ entries = fs7.readdirSync(dir);
1854
2010
  } catch {
1855
2011
  return;
1856
2012
  }
1857
- const graveyard = path6.join(dir, ".sweeping");
2013
+ const graveyard = path7.join(dir, ".sweeping");
1858
2014
  try {
1859
- for (const residue of fs6.readdirSync(graveyard)) {
2015
+ for (const residue of fs7.readdirSync(graveyard)) {
1860
2016
  try {
1861
- fs6.rmSync(path6.join(graveyard, residue), {
2017
+ fs7.rmSync(path7.join(graveyard, residue), {
1862
2018
  recursive: true,
1863
2019
  force: true
1864
2020
  });
@@ -1873,13 +2029,13 @@ var require_dist = __commonJS({
1873
2029
  ].sort((a, b) => (devChannelEpoch(b) ?? -1) - (devChannelEpoch(a) ?? -1));
1874
2030
  const doomed = byNewestFirst.slice(keepCount);
1875
2031
  if (doomed.length === 0) return;
1876
- fs6.mkdirSync(graveyard, {
2032
+ fs7.mkdirSync(graveyard, {
1877
2033
  recursive: true
1878
2034
  });
1879
2035
  for (const entry of doomed) {
1880
- const aside = path6.join(graveyard, `${entry}-${this.now()}`);
2036
+ const aside = path7.join(graveyard, `${entry}-${this.now()}`);
1881
2037
  try {
1882
- fs6.renameSync(path6.join(dir, entry), aside);
2038
+ fs7.renameSync(path7.join(dir, entry), aside);
1883
2039
  } catch (err) {
1884
2040
  this.logger.warn("failed to move dev-uploads entry aside for sweep", {
1885
2041
  meta: {
@@ -1890,7 +2046,7 @@ var require_dist = __commonJS({
1890
2046
  continue;
1891
2047
  }
1892
2048
  try {
1893
- fs6.rmSync(aside, {
2049
+ fs7.rmSync(aside, {
1894
2050
  recursive: true,
1895
2051
  force: true
1896
2052
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.690",
3
+ "version": "1.2.692",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -50,10 +50,10 @@
50
50
  ]
51
51
  },
52
52
  "dependencies": {
53
- "@camstack/addon-admin-ui": "1.2.518",
54
- "@camstack/addon-agent-ui": "1.2.293",
53
+ "@camstack/addon-admin-ui": "1.2.519",
54
+ "@camstack/addon-agent-ui": "1.2.294",
55
55
  "@camstack/addon-auth": "1.2.170",
56
- "@camstack/addon-benchmark": "1.2.292",
56
+ "@camstack/addon-benchmark": "1.2.293",
57
57
  "@camstack/addon-decoder-nodeav": "1.2.144",
58
58
  "@camstack/addon-notifiers": "1.2.623",
59
59
  "@camstack/addon-pipeline": "1.2.634",
@@ -61,9 +61,9 @@
61
61
  "@camstack/addon-post-analysis": "1.2.651",
62
62
  "@camstack/develop": "0.1.39",
63
63
  "@camstack/sdk": "1.2.154",
64
- "@camstack/system": "1.2.519",
65
- "@camstack/types": "1.2.445",
66
- "@camstack/ui-library": "1.2.351",
64
+ "@camstack/system": "1.2.520",
65
+ "@camstack/types": "1.2.446",
66
+ "@camstack/ui-library": "1.2.352",
67
67
  "@fastify/compress": "^9.0.0",
68
68
  "@fastify/cookie": "^11.0.2",
69
69
  "@fastify/cors": "^11.2.0",