@camstack/system 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/dist/addon/addon-api-factory.d.ts +35 -0
  2. package/dist/addon-routes/addon-route-registry.d.ts +37 -0
  3. package/dist/addon-runner.js +599 -0
  4. package/dist/addon-runner.mjs +597 -0
  5. package/dist/auth/api-key-manager.d.ts +26 -0
  6. package/dist/auth/auth-manager.d.ts +109 -0
  7. package/dist/auth/parse-record.d.ts +18 -0
  8. package/dist/auth/scope-matcher.d.ts +7 -0
  9. package/dist/auth/scoped-token-manager.d.ts +40 -0
  10. package/dist/auth/totp-manager.d.ts +51 -0
  11. package/dist/auth/user-manager.d.ts +34 -0
  12. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +53 -0
  13. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +259 -0
  14. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +251 -0
  15. package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +6 -0
  16. package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -0
  17. package/dist/builtins/addon-pages-aggregator/index.js +8 -0
  18. package/dist/builtins/addon-pages-aggregator/index.mjs +2 -0
  19. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +47 -0
  20. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +228 -0
  21. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +220 -0
  22. package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -0
  23. package/dist/builtins/addon-widgets-aggregator/index.js +8 -0
  24. package/dist/builtins/addon-widgets-aggregator/index.mjs +2 -0
  25. package/dist/builtins/alerts/alerts.addon.d.ts +81 -0
  26. package/dist/builtins/alerts/alerts.addon.js +601 -0
  27. package/dist/builtins/alerts/alerts.addon.mjs +595 -0
  28. package/dist/builtins/alerts/index.d.ts +1 -0
  29. package/dist/builtins/alerts/index.js +4 -0
  30. package/dist/builtins/alerts/index.mjs +2 -0
  31. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +147 -0
  32. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2229 -0
  33. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2220 -0
  34. package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +23 -0
  35. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +72 -0
  36. package/dist/builtins/backup-orchestrator/download-helpers.d.ts +12 -0
  37. package/dist/builtins/backup-orchestrator/index.d.ts +2 -0
  38. package/dist/builtins/backup-orchestrator/index.js +8 -0
  39. package/dist/builtins/backup-orchestrator/index.mjs +2 -0
  40. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +77 -0
  41. package/dist/builtins/console-logging/console-destination.d.ts +13 -0
  42. package/dist/builtins/console-logging/console-logging.addon.d.ts +25 -0
  43. package/dist/builtins/console-logging/index.d.ts +3 -0
  44. package/dist/builtins/console-logging/index.js +104 -0
  45. package/dist/builtins/console-logging/index.mjs +95 -0
  46. package/dist/builtins/device-manager/device-config-contribution.d.ts +32 -0
  47. package/dist/builtins/device-manager/device-event-propagator.d.ts +26 -0
  48. package/dist/builtins/device-manager/device-link-overlay.d.ts +23 -0
  49. package/dist/builtins/device-manager/device-link-resolver.d.ts +15 -0
  50. package/dist/builtins/device-manager/device-manager.addon.d.ts +452 -0
  51. package/dist/builtins/device-manager/device-manager.addon.js +3299 -0
  52. package/dist/builtins/device-manager/device-manager.addon.mjs +3292 -0
  53. package/dist/builtins/device-manager/index.d.ts +2 -0
  54. package/dist/builtins/device-manager/index.js +8 -0
  55. package/dist/builtins/device-manager/index.mjs +2 -0
  56. package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +44 -0
  57. package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +15 -0
  58. package/dist/builtins/hub-forwarder/index.d.ts +3 -0
  59. package/dist/builtins/hub-forwarder/index.js +154 -0
  60. package/dist/builtins/hub-forwarder/index.mjs +145 -0
  61. package/dist/builtins/local-auth/auth-schema.d.ts +26 -0
  62. package/dist/builtins/local-auth/index.d.ts +1 -0
  63. package/dist/builtins/local-auth/index.js +4 -0
  64. package/dist/builtins/local-auth/index.mjs +2 -0
  65. package/dist/builtins/local-auth/local-auth.addon.d.ts +18 -0
  66. package/dist/builtins/local-auth/local-auth.addon.js +8094 -0
  67. package/dist/builtins/local-auth/local-auth.addon.mjs +8063 -0
  68. package/dist/builtins/local-auth/oauth-grants.d.ts +45 -0
  69. package/dist/builtins/local-auth/oauth-session-manager.d.ts +50 -0
  70. package/dist/builtins/local-network/index.d.ts +2 -0
  71. package/dist/builtins/local-network/index.js +10 -0
  72. package/dist/builtins/local-network/index.mjs +2 -0
  73. package/dist/builtins/local-network/local-network.addon.d.ts +150 -0
  74. package/dist/builtins/local-network/local-network.addon.js +489 -0
  75. package/dist/builtins/local-network/local-network.addon.mjs +477 -0
  76. package/dist/builtins/native-metrics/index.d.ts +2 -0
  77. package/dist/builtins/native-metrics/native-metrics-provider.d.ts +48 -0
  78. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +73 -0
  79. package/dist/builtins/native-metrics/native-metrics.addon.js +922 -0
  80. package/dist/builtins/native-metrics/native-metrics.addon.mjs +914 -0
  81. package/dist/builtins/platform-probe/hardware-decode-accel-probe.d.ts +37 -0
  82. package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +13 -0
  83. package/dist/builtins/platform-probe/index.d.ts +22 -0
  84. package/dist/builtins/platform-probe/index.js +834 -0
  85. package/dist/builtins/platform-probe/index.mjs +822 -0
  86. package/dist/builtins/platform-probe/inference-config-resolver.d.ts +29 -0
  87. package/dist/builtins/platform-probe/intel-accelerators.d.ts +11 -0
  88. package/dist/builtins/platform-probe/platform-scorer.d.ts +30 -0
  89. package/dist/builtins/platform-probe/runtime-packages.d.ts +6 -0
  90. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +96 -0
  91. package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -0
  92. package/dist/builtins/remote-access-orchestrator/index.js +8 -0
  93. package/dist/builtins/remote-access-orchestrator/index.mjs +2 -0
  94. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +40 -0
  95. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +214 -0
  96. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +208 -0
  97. package/dist/builtins/shared/settle-sources.d.ts +22 -0
  98. package/dist/builtins/snapshot/index.d.ts +2 -0
  99. package/dist/builtins/snapshot/index.js +494 -0
  100. package/dist/builtins/snapshot/index.mjs +488 -0
  101. package/dist/builtins/snapshot/snapshot.addon.d.ts +120 -0
  102. package/dist/builtins/sqlite-storage/config-store.d.ts +8 -0
  103. package/dist/builtins/sqlite-storage/device-store.d.ts +23 -0
  104. package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +25 -0
  105. package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +83 -0
  106. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +32 -0
  107. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +396 -0
  108. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +388 -0
  109. package/dist/builtins/sqlite-storage/index.d.ts +8 -0
  110. package/dist/builtins/sqlite-storage/index.js +62 -0
  111. package/dist/builtins/sqlite-storage/index.mjs +49 -0
  112. package/dist/builtins/sqlite-storage/integration-registry.d.ts +27 -0
  113. package/dist/builtins/sqlite-storage/path-guard.d.ts +4 -0
  114. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +102 -0
  115. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +14 -0
  116. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +644 -0
  117. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +636 -0
  118. package/dist/builtins/storage-orchestrator/index.d.ts +6 -0
  119. package/dist/builtins/storage-orchestrator/index.js +10 -0
  120. package/dist/builtins/storage-orchestrator/index.mjs +2 -0
  121. package/dist/builtins/storage-orchestrator/location-store.d.ts +49 -0
  122. package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +10 -0
  123. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +103 -0
  124. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1138 -0
  125. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1128 -0
  126. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +236 -0
  127. package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +38 -0
  128. package/dist/builtins/system-backup/system-backup.service.d.ts +137 -0
  129. package/dist/builtins/system-config/index.d.ts +1 -0
  130. package/dist/builtins/system-config/index.js +8 -0
  131. package/dist/builtins/system-config/index.mjs +2 -0
  132. package/dist/builtins/system-config/system-config.addon.d.ts +10 -0
  133. package/dist/builtins/system-config/system-config.addon.js +232 -0
  134. package/dist/builtins/system-config/system-config.addon.mjs +226 -0
  135. package/dist/builtins/winston-logging/index.d.ts +3 -0
  136. package/dist/builtins/winston-logging/index.js +156 -0
  137. package/dist/builtins/winston-logging/index.mjs +144 -0
  138. package/dist/builtins/winston-logging/winston-destination.d.ts +21 -0
  139. package/dist/builtins/winston-logging/winston-logging.addon.d.ts +19 -0
  140. package/dist/chunk-CNf5ZN-e.mjs +37 -0
  141. package/dist/chunk-Cek0wNdY.js +64 -0
  142. package/dist/download/model-download-service.d.ts +41 -0
  143. package/dist/download/model-downloader.d.ts +31 -0
  144. package/dist/events/event-bus.d.ts +10 -0
  145. package/dist/events/system-event-bus.d.ts +14 -0
  146. package/dist/feature/feature-manager.d.ts +11 -0
  147. package/dist/formatter-B7qW8bPJ.mjs +162 -0
  148. package/dist/formatter-DqAKDlvN.js +167 -0
  149. package/dist/http/authenticated-file-server.d.ts +53 -0
  150. package/dist/http/data-plane-registry.d.ts +23 -0
  151. package/dist/http/file-data-plane.d.ts +10 -0
  152. package/dist/http/reverse-proxy.d.ts +15 -0
  153. package/dist/index.d.ts +82 -0
  154. package/dist/index.js +93485 -0
  155. package/dist/index.mjs +93179 -0
  156. package/dist/intel-accelerators-Gg0P5mnl.js +20 -0
  157. package/dist/intel-accelerators-hGgpZ0pX.mjs +19 -0
  158. package/dist/kernel/addon-class-resolver.d.ts +4 -0
  159. package/dist/kernel/addon-engine-manager.d.ts +22 -0
  160. package/dist/kernel/addon-health-monitor.d.ts +154 -0
  161. package/dist/kernel/addon-installer.d.ts +208 -0
  162. package/dist/kernel/addon-loader.d.ts +106 -0
  163. package/dist/kernel/addon-manifest.d.ts +77 -0
  164. package/dist/kernel/capability-handle.d.ts +46 -0
  165. package/dist/kernel/capability-registry.d.ts +412 -0
  166. package/dist/kernel/config-manager.d.ts +212 -0
  167. package/dist/kernel/config-schema.d.ts +93 -0
  168. package/dist/kernel/custom-action-registry.d.ts +23 -0
  169. package/dist/kernel/deps/addon-deps-manager.d.ts +19 -0
  170. package/dist/kernel/deps/manifest-native-deps.d.ts +25 -0
  171. package/dist/kernel/deps/manifest-python-deps.d.ts +20 -0
  172. package/dist/kernel/device-registry.d.ts +29 -0
  173. package/dist/kernel/fs-utils.d.ts +41 -0
  174. package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +19 -0
  175. package/dist/kernel/hwaccel/hwaccel-service.d.ts +4 -0
  176. package/dist/kernel/index.d.ts +74 -0
  177. package/dist/kernel/infra-capabilities.d.ts +13 -0
  178. package/dist/kernel/moleculer/addon-context-factory.d.ts +91 -0
  179. package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +19 -0
  180. package/dist/kernel/moleculer/addon-runner.d.ts +1 -0
  181. package/dist/kernel/moleculer/addon-service-factory.d.ts +50 -0
  182. package/dist/kernel/moleculer/broker-factory.d.ts +50 -0
  183. package/dist/kernel/moleculer/cap-usage-registry.d.ts +46 -0
  184. package/dist/kernel/moleculer/capabilities-access.d.ts +21 -0
  185. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +46 -0
  186. package/dist/kernel/moleculer/child-cap-dispatch.d.ts +20 -0
  187. package/dist/kernel/moleculer/cluster-secret.d.ts +15 -0
  188. package/dist/kernel/moleculer/core-cap-service.d.ts +50 -0
  189. package/dist/kernel/moleculer/crash-supervisor.d.ts +50 -0
  190. package/dist/kernel/moleculer/device-cap-proxy.d.ts +79 -0
  191. package/dist/kernel/moleculer/event-bus-core.d.ts +53 -0
  192. package/dist/kernel/moleculer/event-bus.d.ts +53 -0
  193. package/dist/kernel/moleculer/hub-log-forwarder.d.ts +36 -0
  194. package/dist/kernel/moleculer/hub-service.d.ts +35 -0
  195. package/dist/kernel/moleculer/node-registry.d.ts +126 -0
  196. package/dist/kernel/moleculer/process-context.d.ts +4 -0
  197. package/dist/kernel/moleculer/process-service.d.ts +72 -0
  198. package/dist/kernel/moleculer/provider-registry.d.ts +28 -0
  199. package/dist/kernel/moleculer/readiness-context.d.ts +62 -0
  200. package/dist/kernel/moleculer/readiness-service.d.ts +7 -0
  201. package/dist/kernel/moleculer/register-node-client.d.ts +35 -0
  202. package/dist/kernel/moleculer/remote-logger.d.ts +43 -0
  203. package/dist/kernel/moleculer/resilient-cap-call.d.ts +28 -0
  204. package/dist/kernel/moleculer/stream-probe-service.d.ts +9 -0
  205. package/dist/kernel/moleculer/trpc-links.d.ts +189 -0
  206. package/dist/kernel/moleculer/typed-array-serde.d.ts +25 -0
  207. package/dist/kernel/moleculer/worker-device-restore.d.ts +10 -0
  208. package/dist/kernel/provider-kind-drift.d.ts +12 -0
  209. package/dist/kernel/restart-coordinator.d.ts +90 -0
  210. package/dist/kernel/storage-location-registry.d.ts +40 -0
  211. package/dist/kernel/transport/cap-action-name.d.ts +100 -0
  212. package/dist/kernel/transport/cap-route-resolver.d.ts +148 -0
  213. package/dist/kernel/transport/cap-route.d.ts +148 -0
  214. package/dist/kernel/transport/child-cap-protocol.d.ts +136 -0
  215. package/dist/kernel/transport/create-local-transport.d.ts +7 -0
  216. package/dist/kernel/transport/frame-codec.d.ts +7 -0
  217. package/dist/kernel/transport/index.d.ts +27 -0
  218. package/dist/kernel/transport/local-child-client.d.ts +136 -0
  219. package/dist/kernel/transport/local-child-registry.d.ts +179 -0
  220. package/dist/kernel/transport/local-endpoint-path.d.ts +6 -0
  221. package/dist/kernel/transport/local-transport.d.ts +46 -0
  222. package/dist/kernel/transport/parent-unowned-call.d.ts +75 -0
  223. package/dist/kernel/transport/socket-channel.d.ts +27 -0
  224. package/dist/kernel/transport/uds-event-bridge.d.ts +36 -0
  225. package/dist/kernel/transport/uds-event-bus.d.ts +22 -0
  226. package/dist/kernel/transport/uds-local-transport.d.ts +18 -0
  227. package/dist/kernel/transport/uds-log-ingest.d.ts +28 -0
  228. package/dist/kernel/transport/uds-logger.d.ts +44 -0
  229. package/dist/kernel/utils/ring-buffer.d.ts +15 -0
  230. package/dist/kernel/workspace-detect.d.ts +9 -0
  231. package/dist/lifecycle/lifecycle-state-machine.d.ts +28 -0
  232. package/dist/logging/formatter.d.ts +30 -0
  233. package/dist/logging/log-manager.d.ts +54 -0
  234. package/dist/logging/log-ring-buffer.d.ts +47 -0
  235. package/dist/logging/partitioned-log-buffer.d.ts +35 -0
  236. package/dist/logging/scoped-logger.d.ts +17 -0
  237. package/dist/main-DNnMW7Z2.js +9983 -0
  238. package/dist/main-rtjOwPBR.mjs +9976 -0
  239. package/dist/manifest-python-deps-D1DbAQEv.js +6724 -0
  240. package/dist/manifest-python-deps-DZsKTbs1.mjs +6315 -0
  241. package/dist/network/network-quality.d.ts +11 -0
  242. package/dist/notification/notification-service.d.ts +37 -0
  243. package/dist/notification/toast-service.d.ts +22 -0
  244. package/dist/pipeline/engine-manager-resolver.d.ts +15 -0
  245. package/dist/pipeline/pipeline-runner.d.ts +8 -0
  246. package/dist/pipeline/pipeline-validator.d.ts +13 -0
  247. package/dist/process/resource-monitor.d.ts +11 -0
  248. package/dist/python/python-env-manager.d.ts +12 -0
  249. package/dist/repl/interfaces.d.ts +31 -0
  250. package/dist/repl/repl-engine.d.ts +8 -0
  251. package/dist/resource-monitor-ClDGFyf6.mjs +57 -0
  252. package/dist/resource-monitor-IIEanuJt.js +74 -0
  253. package/dist/settle-sources-Bhsy57y-.js +38 -0
  254. package/dist/settle-sources-CDtNC8ub.mjs +33 -0
  255. package/dist/storage/fs-storage-backend.d.ts +40 -0
  256. package/dist/storage/storage-location-manager.d.ts +23 -0
  257. package/dist/storage/storage-manager.d.ts +83 -0
  258. package/dist/tar-BgAEMRBR.js +5434 -0
  259. package/dist/tar-ByMOPNM0.mjs +5429 -0
  260. package/dist/tls/cert-manager.d.ts +26 -0
  261. package/dist/tls/index.d.ts +1 -0
  262. package/package.json +343 -0
@@ -0,0 +1,477 @@
1
+ import { BaseAddon, EventCategory, localNetworkCapability } from "@camstack/types";
2
+ import * as os from "node:os";
3
+ //#region src/builtins/local-network/local-network.addon.ts
4
+ /**
5
+ * local-network — hub-only system cap implementation.
6
+ *
7
+ * Wraps `os.networkInterfaces()` with:
8
+ * - Coarse kind classification (lan/wifi/docker/vpn/loopback/other)
9
+ * - Auto-select heuristic for the outbound interface
10
+ * - Periodic poll (30s) + diff to emit `LocalNetworkChanged` events
11
+ * so subscribers can react to DHCP renewals, VPN connect, etc.
12
+ * - `getConnectionEndpoints()` — ranked URL list for SDK clients
13
+ *
14
+ * Does NOT poll the cloudflare-tunnel state directly; the public
15
+ * tunnel hostname (if any) is provided by `network-access` consumers
16
+ * via `NetworkTunnelStarted/Stopped` events on the bus, so the cap
17
+ * stays free of cross-addon dependencies.
18
+ */
19
+ /**
20
+ * Forked `mesh-network` provider addon ids `local-network` pull-reconciles
21
+ * against. `mesh-network` is a COLLECTION cap, so a hub builtin's local
22
+ * registry can't enumerate forked providers — we resolve each by addonId
23
+ * via `getProviderByAddon`. New mesh providers (Headscale, ZeroTier) add
24
+ * their id here.
25
+ */
26
+ var MESH_PROVIDER_ADDON_IDS = ["tailscale-client"];
27
+ var POLL_INTERVAL_MS = 3e4;
28
+ var LocalNetworkAddon = class extends BaseAddon {
29
+ pollTimer = null;
30
+ lastSnapshotKey = "";
31
+ /** Optional public hostname tracked from `NetworkTunnelStarted`/
32
+ * `Stopped` events on the bus. */
33
+ publicHostname = "";
34
+ /**
35
+ * Mesh-reachable endpoint (Tailscale MagicDNS / 100.x), learned from
36
+ * the `MeshNetworkChanged` event-tail and refreshed by a pull-reconcile
37
+ * before each `getConnectionEndpoints` build (events are lossy — D8).
38
+ * `null` when no mesh provider is joined.
39
+ */
40
+ meshEndpoint = null;
41
+ constructor() {
42
+ super({
43
+ allowedAddresses: [],
44
+ bootSeeded: false
45
+ });
46
+ }
47
+ async onInitialize() {
48
+ if (!this.config.bootSeeded) {
49
+ const seed = autoSeedAllowlist(this.enumerate());
50
+ await this.updateGlobalSettings({
51
+ allowedAddresses: seed,
52
+ bootSeeded: true
53
+ });
54
+ this.ctx.logger.info("local-network: first-boot auto-seed", { meta: { addresses: seed } });
55
+ }
56
+ const provider = {
57
+ list: async () => ({
58
+ interfaces: this.enumerate(),
59
+ probedAt: Date.now()
60
+ }),
61
+ getPreferred: async () => pickPreferred(applyAllowlist(this.enumerate(), this.config.allowedAddresses)),
62
+ getConnectionEndpoints: async (input) => {
63
+ const includeLoopback = input.includeLoopback ?? true;
64
+ const ipv4Only = input.ipv4Only ?? false;
65
+ const scheme = input.scheme ?? "http";
66
+ const allow = this.config.allowedAddresses;
67
+ const interfaces = applyAllowlist(this.enumerate(), allow);
68
+ await this.reconcileMeshEndpoint();
69
+ return { endpoints: buildEndpoints(interfaces, input.port, includeLoopback, ipv4Only, this.publicHostname, scheme, this.meshEndpoint) };
70
+ },
71
+ getAllowedAddresses: async () => ({ addresses: this.config.allowedAddresses }),
72
+ resetAllowlistToBestMatch: async () => {
73
+ const seed = autoSeedAllowlist(this.enumerate());
74
+ await this.updateGlobalSettings({
75
+ allowedAddresses: seed,
76
+ bootSeeded: true
77
+ });
78
+ this.ctx.logger.info("local-network: allowlist reset to auto-seed", { meta: { count: seed.length } });
79
+ return { addresses: seed };
80
+ },
81
+ setAllowedAddresses: async ({ addresses }) => {
82
+ const known = new Set(this.enumerate().map((i) => i.address));
83
+ const cleaned = [...new Set(addresses)].filter((a) => known.has(a));
84
+ await this.updateGlobalSettings({ allowedAddresses: cleaned });
85
+ this.ctx.logger.info("local-network: allowlist updated", { meta: {
86
+ count: cleaned.length,
87
+ dropped: addresses.length - cleaned.length
88
+ } });
89
+ return { success: true };
90
+ }
91
+ };
92
+ this.lastSnapshotKey = snapshotKey(this.enumerate());
93
+ this.pollTimer = setInterval(() => this.detectChanges(), POLL_INTERVAL_MS);
94
+ this.pollTimer.unref?.();
95
+ this.ctx.eventBus?.subscribe({ category: EventCategory.NetworkTunnelStarted }, (event) => {
96
+ const data = event.data ?? {};
97
+ if (typeof data.url === "string") try {
98
+ const hostname = new URL(data.url).hostname;
99
+ if (hostname && !hostname.endsWith(".placeholder") && !hostname.startsWith("pending.")) this.setPublicHostname(hostname);
100
+ } catch {}
101
+ });
102
+ this.ctx.eventBus?.subscribe({ category: EventCategory.NetworkTunnelStopped }, () => this.setPublicHostname(""));
103
+ this.ctx.eventBus?.subscribe({ category: EventCategory.MeshNetworkChanged }, (event) => {
104
+ const data = event.data ?? {};
105
+ const host = typeof data.host === "string" ? data.host : "";
106
+ const port = typeof data.port === "number" ? data.port : 0;
107
+ this.setMeshEndpoint(host && port > 0 ? {
108
+ host,
109
+ port
110
+ } : null);
111
+ });
112
+ this.ctx.logger.info("local-network initialized", { meta: { interfaceCount: this.enumerate().length } });
113
+ return [{
114
+ capability: localNetworkCapability,
115
+ provider
116
+ }];
117
+ }
118
+ async onShutdown() {
119
+ if (this.pollTimer) {
120
+ clearInterval(this.pollTimer);
121
+ this.pollTimer = null;
122
+ }
123
+ }
124
+ /**
125
+ * Other hub addons (e.g. cloudflare-tunnel) signal the active public
126
+ * FQDN by emitting `NetworkTunnelStarted` on the bus — handled in
127
+ * `onInitialize`. This setter exists for tests + future direct
128
+ * callers; cleared by passing an empty string.
129
+ */
130
+ setPublicHostname(hostname) {
131
+ if (this.publicHostname === hostname) return;
132
+ this.publicHostname = hostname;
133
+ this.ctx.logger.info("local-network: public hostname updated", { meta: { hostname: hostname || "(cleared)" } });
134
+ }
135
+ /**
136
+ * Replace the cached mesh endpoint. Set from the `MeshNetworkChanged`
137
+ * event-tail + the pull-reconcile; exposed for tests + future direct
138
+ * callers. Pass `null` to clear (mesh left / no provider joined).
139
+ */
140
+ setMeshEndpoint(endpoint) {
141
+ const prev = this.meshEndpoint;
142
+ if (prev?.host === endpoint?.host && prev?.port === endpoint?.port) return;
143
+ this.meshEndpoint = endpoint;
144
+ this.ctx.logger.info("local-network: mesh endpoint updated", { meta: {
145
+ host: endpoint?.host || "(cleared)",
146
+ port: endpoint?.port ?? 0
147
+ } });
148
+ }
149
+ /**
150
+ * Refresh the cached mesh endpoint from the authoritative forked
151
+ * `mesh-network` provider(s). `mesh-network` is a COLLECTION cap on a
152
+ * forked addon, so the hub builtin can't see it via `ctx.api` /
153
+ * `getCollectionEntries` — we resolve each provider by addonId through
154
+ * the hub-side `capabilityRegistry.getProviderByAddon` resolver (the
155
+ * same mechanism `device-manager` uses for cross-process exporter
156
+ * contributions). Best-effort: a provider that's absent / errors /
157
+ * not joined simply contributes nothing.
158
+ */
159
+ async reconcileMeshEndpoint() {
160
+ const registry = this.ctx.kernel.capabilityRegistry;
161
+ if (!registry) return;
162
+ for (const addonId of MESH_PROVIDER_ADDON_IDS) {
163
+ const provider = registry.getProviderByAddon("mesh-network", addonId);
164
+ if (!provider) continue;
165
+ try {
166
+ const status = await provider.getStatus();
167
+ if (!status.joined) {
168
+ this.setMeshEndpoint(null);
169
+ continue;
170
+ }
171
+ const host = status.magicDnsHostname || status.meshIp;
172
+ const port = (status.endpoints.find((e) => e.id === "magicdns") ?? status.endpoints.find((e) => e.id === "mesh-ipv4"))?.port ?? 0;
173
+ this.setMeshEndpoint(host && port > 0 ? {
174
+ host,
175
+ port
176
+ } : null);
177
+ return;
178
+ } catch (err) {
179
+ this.ctx.logger.debug("local-network: mesh reconcile skipped", { meta: {
180
+ addonId,
181
+ error: err instanceof Error ? err.message : String(err)
182
+ } });
183
+ }
184
+ }
185
+ }
186
+ enumerate() {
187
+ return enumerateOsInterfaces(os.networkInterfaces());
188
+ }
189
+ detectChanges() {
190
+ const interfaces = this.enumerate();
191
+ const key = snapshotKey(interfaces);
192
+ if (key === this.lastSnapshotKey) return;
193
+ this.ctx.logger.info("local-network: interface set changed", { meta: {
194
+ count: interfaces.length,
195
+ key
196
+ } });
197
+ this.lastSnapshotKey = key;
198
+ this.ctx.eventBus?.emit({
199
+ id: `local-network-changed-${Date.now()}`,
200
+ timestamp: /* @__PURE__ */ new Date(),
201
+ source: {
202
+ type: "core",
203
+ id: "local-network"
204
+ },
205
+ category: EventCategory.LocalNetworkChanged,
206
+ data: { count: interfaces.length }
207
+ });
208
+ }
209
+ };
210
+ function enumerateOsInterfaces(ifaces) {
211
+ const raw = [];
212
+ for (const [name, addrs] of Object.entries(ifaces)) {
213
+ if (!addrs) continue;
214
+ for (const a of addrs) {
215
+ if (a.family !== "IPv4" && a.family !== "IPv6") continue;
216
+ raw.push({
217
+ name,
218
+ family: a.family,
219
+ address: a.address,
220
+ cidr: a.cidr ?? "",
221
+ netmask: a.netmask,
222
+ internal: a.internal,
223
+ mac: a.mac
224
+ });
225
+ }
226
+ }
227
+ const classified = raw.map((r) => {
228
+ const kind = classifyKind(r.name, r.address, r.internal);
229
+ const reachableKind = kind === "lan" || kind === "wifi";
230
+ const plausible = !r.internal && reachableKind && isPlausibleAutoSeed(r.address, r.family);
231
+ const plausibleReason = plausible ? "" : explainNonPlausible({
232
+ kind,
233
+ family: r.family,
234
+ address: r.address,
235
+ internal: r.internal
236
+ });
237
+ return {
238
+ name: r.name,
239
+ family: r.family,
240
+ address: r.address,
241
+ cidr: r.cidr,
242
+ netmask: r.netmask,
243
+ internal: r.internal,
244
+ mac: r.mac,
245
+ kind,
246
+ preferred: false,
247
+ plausible,
248
+ plausibleReason
249
+ };
250
+ });
251
+ const preferred = pickPreferred(classified);
252
+ return classified.map((iface) => ({
253
+ ...iface,
254
+ preferred: preferred !== null && iface.name === preferred.name && iface.address === preferred.address
255
+ }));
256
+ }
257
+ /**
258
+ * Filter the interface list by the operator's allowlist. Empty
259
+ * allowlist = no-op (every interface passes); otherwise only entries
260
+ * whose `address` matches an allowlist entry remain. Loopback always
261
+ * survives so the SDK keeps `127.0.0.1` as the last-resort fallback.
262
+ */
263
+ function applyAllowlist(interfaces, allowed) {
264
+ if (allowed.length === 0) return interfaces;
265
+ const set = new Set(allowed);
266
+ return interfaces.filter((i) => i.kind === "loopback" || set.has(i.address));
267
+ }
268
+ /**
269
+ * Rank interfaces and pick the auto-selected outbound one. See the
270
+ * cap's `getPreferred` doc for the heuristic.
271
+ */
272
+ function pickPreferred(interfaces) {
273
+ const candidates = interfaces.filter((i) => !i.internal && i.family === "IPv4" && !i.address.startsWith("169.254.") && i.kind !== "loopback");
274
+ if (candidates.length === 0) return null;
275
+ const kindRank = {
276
+ lan: 1,
277
+ wifi: 2,
278
+ vpn: 3,
279
+ docker: 4,
280
+ other: 5,
281
+ loopback: 99
282
+ };
283
+ return [...candidates].toSorted((a, b) => {
284
+ const ra = kindRank[a.kind];
285
+ const rb = kindRank[b.kind];
286
+ if (ra !== rb) return ra - rb;
287
+ return prefixLen(b.netmask) - prefixLen(a.netmask);
288
+ })[0] ?? null;
289
+ }
290
+ /**
291
+ * Build the ordered candidate URL list. Priority schema:
292
+ * 0 — preferred LAN IPv4
293
+ * 10+ — other LAN IPv4
294
+ * 100 — public tunnel hostname (always HTTPS)
295
+ * 150 — mesh endpoint (Tailscale MagicDNS / 100.x, always HTTPS)
296
+ * 200+ — LAN IPv6
297
+ * 1000 — loopback (last resort)
298
+ *
299
+ * The mesh endpoint ranks just below a true public funnel (a Funnel is
300
+ * reachable by ANY client; the mesh needs the peer on the same tailnet)
301
+ * but above the IPv6 / loopback fallbacks — giving remote, mesh-joined
302
+ * clients a working candidate when no public tunnel is up.
303
+ *
304
+ * `scheme` controls LAN + loopback URLs. Browsers running over HTTPS
305
+ * block `http://` candidates as mixed content, so callers loaded over
306
+ * HTTPS should pass `scheme: 'https'` even when probing a LAN IP — the
307
+ * hub's cert manager already issues a SAN-multi cert covering local
308
+ * interfaces. The public tunnel + mesh endpoint always emit `https://`
309
+ * (the tunnel edge / the hub itself terminates TLS).
310
+ */
311
+ function buildEndpoints(interfaces, port, includeLoopback, ipv4Only, publicHostname, scheme = "http", meshEndpoint = null) {
312
+ const out = [];
313
+ let priority = 0;
314
+ const preferred = pickPreferred(interfaces);
315
+ const emit = (iface, kind, label, baseUrl, pri) => {
316
+ out.push({
317
+ label,
318
+ baseUrl,
319
+ kind,
320
+ interfaceKind: iface.kind,
321
+ plausible: iface.plausible,
322
+ plausibleReason: iface.plausibleReason,
323
+ priority: pri
324
+ });
325
+ };
326
+ if (preferred) emit(preferred, "lan-ipv4", `${formatKind(preferred.kind)} — ${preferred.name}`, `${scheme}://${preferred.address}:${port}`, priority++);
327
+ for (const iface of interfaces) {
328
+ if (iface.internal || iface.family !== "IPv4") continue;
329
+ if (iface.kind === "loopback") continue;
330
+ if (preferred && iface.name === preferred.name && iface.address === preferred.address) continue;
331
+ if (iface.address.startsWith("169.254.")) continue;
332
+ emit(iface, "lan-ipv4", `${formatKind(iface.kind)} — ${iface.name}`, `${scheme}://${iface.address}:${port}`, 10 + priority++);
333
+ }
334
+ if (publicHostname) out.push({
335
+ label: "Public tunnel",
336
+ baseUrl: `https://${publicHostname}`,
337
+ kind: "public",
338
+ interfaceKind: "public",
339
+ plausible: true,
340
+ plausibleReason: "",
341
+ priority: 100
342
+ });
343
+ if (meshEndpoint && meshEndpoint.host) out.push({
344
+ label: "Mesh (Tailscale)",
345
+ baseUrl: `https://${meshEndpoint.host}:${meshEndpoint.port}`,
346
+ kind: "public",
347
+ interfaceKind: "vpn",
348
+ plausible: true,
349
+ plausibleReason: "",
350
+ priority: 150
351
+ });
352
+ if (!ipv4Only) {
353
+ let v6prio = 200;
354
+ for (const iface of interfaces) {
355
+ if (iface.internal || iface.family !== "IPv6") continue;
356
+ if (iface.kind === "loopback") continue;
357
+ if (iface.address.startsWith("fe80:")) continue;
358
+ emit(iface, "lan-ipv6", `${formatKind(iface.kind)} — ${iface.name} (IPv6)`, `${scheme}://[${iface.address}]:${port}`, v6prio++);
359
+ }
360
+ }
361
+ if (includeLoopback) out.push({
362
+ label: "Loopback",
363
+ baseUrl: `${scheme}://127.0.0.1:${port}`,
364
+ kind: "loopback",
365
+ interfaceKind: "loopback",
366
+ plausible: false,
367
+ plausibleReason: "Loopback — last-resort fallback when no other endpoint responds.",
368
+ priority: 1e3
369
+ });
370
+ return out.toSorted((a, b) => a.priority - b.priority);
371
+ }
372
+ /**
373
+ * First-boot heuristic: which addresses should the allowlist start
374
+ * with? Includes LAN + Wi-Fi IPv4 addresses + plausible IPv6:
375
+ *
376
+ * - **IPv4**: skip link-local (`169.254.*`), keep the rest.
377
+ * - **IPv6**: skip link-local (`fe80::*`), unspecified, and
378
+ * multicast. Keep ULAs (`fc00::/7` → `fc??:` / `fd??:`) and Global
379
+ * Unicast addresses (`2000::/3` → `2???`/`3???`). Privacy-extension
380
+ * temporary addresses get included by default; the operator can
381
+ * prune them from the Network Addresses tab if the rotating IPs
382
+ * become a nuisance.
383
+ *
384
+ * Skips docker/vpn/loopback/other entirely — those stay opt-in.
385
+ */
386
+ function autoSeedAllowlist(interfaces) {
387
+ return [...new Set(interfaces.filter((i) => !i.internal && (i.kind === "lan" || i.kind === "wifi") && isPlausibleAutoSeed(i.address, i.family)).map((i) => i.address))];
388
+ }
389
+ /**
390
+ * Per-interface tooltip text surfaced on the "Unlikely usable" badge.
391
+ * Server-side so the UI doesn't re-derive the rationale (single source
392
+ * of truth). Returns `''` for plausible entries; the addon overlays
393
+ * this on the `LocalInterface.plausibleReason` field.
394
+ */
395
+ function explainNonPlausible(input) {
396
+ if (input.internal) return "Internal interface (loopback) — not reachable from clients.";
397
+ if (input.kind === "docker") return "Docker bridge — only reachable from inside the container network.";
398
+ if (input.kind === "vpn") return "VPN tunnel — only reachable while the VPN is connected.";
399
+ if (input.kind === "other") return "Unrecognised interface kind — verify reachability before pinning.";
400
+ if (input.family === "IPv6") {
401
+ const a = input.address.toLowerCase();
402
+ if (a.startsWith("fe80:")) return "IPv6 link-local — only reachable on the same link, not routed.";
403
+ if (a.startsWith("ff")) return "IPv6 multicast — not a unicast address.";
404
+ if (a === "::" || a === "::1") return "IPv6 loopback / unspecified — not a public address.";
405
+ return "IPv6 address outside the ULA / GUA ranges — verify before pinning.";
406
+ }
407
+ if (input.address.startsWith("169.254.")) return "IPv4 link-local (RFC 3927) — only valid when DHCP fails.";
408
+ return "Address looks unusual for client traffic — verify before pinning.";
409
+ }
410
+ /**
411
+ * Per-address gate used by `autoSeedAllowlist`. Exposed for tests so
412
+ * we can pin every classification rule without standing up the addon.
413
+ */
414
+ function isPlausibleAutoSeed(address, family) {
415
+ if (family === "IPv4") {
416
+ if (address.startsWith("169.254.")) return false;
417
+ return true;
418
+ }
419
+ const a = address.toLowerCase();
420
+ if (a === "::" || a === "::1") return false;
421
+ if (a.startsWith("fe80:")) return false;
422
+ if (a.startsWith("ff")) return false;
423
+ if (/^f[cd][0-9a-f]{0,2}:/.test(a)) return true;
424
+ if (/^[23][0-9a-f]{0,3}:/.test(a)) return true;
425
+ return false;
426
+ }
427
+ function classifyKind(name, address, internal) {
428
+ if (internal || name === "lo" || name.startsWith("lo")) return "loopback";
429
+ const n = name.toLowerCase();
430
+ if (n.startsWith("docker") || n.startsWith("br-") || n.startsWith("veth")) return "docker";
431
+ if (n.startsWith("tun") || n.startsWith("utun") || n.startsWith("wg") || n.startsWith("tap")) return "vpn";
432
+ if (n.startsWith("wlan") || n.startsWith("wlp") || n.startsWith("wlx")) return "wifi";
433
+ if (n.startsWith("eth") || /^en\d+$/.test(n)) {
434
+ if (process.platform === "darwin" && /^en[1-9]\d*$/.test(n)) return "wifi";
435
+ return "lan";
436
+ }
437
+ if (address === "127.0.0.1" || address === "::1") return "loopback";
438
+ return "other";
439
+ }
440
+ /** Convert an IPv4/IPv6 netmask string to its prefix length (CIDR). */
441
+ function prefixLen(netmask) {
442
+ if (!netmask) return 0;
443
+ if (netmask.includes(":")) {
444
+ let bits = 0;
445
+ for (const group of netmask.split(":")) {
446
+ if (!group) continue;
447
+ const n = parseInt(group, 16);
448
+ if (!Number.isFinite(n)) break;
449
+ for (let mask = 32768; mask; mask >>= 1) if (n & mask) bits++;
450
+ else return bits;
451
+ }
452
+ return bits;
453
+ }
454
+ let bits = 0;
455
+ for (const part of netmask.split(".")) {
456
+ const n = parseInt(part, 10);
457
+ if (!Number.isFinite(n)) break;
458
+ for (let mask = 128; mask; mask >>= 1) if (n & mask) bits++;
459
+ else return bits;
460
+ }
461
+ return bits;
462
+ }
463
+ function snapshotKey(interfaces) {
464
+ return [...interfaces].map((i) => `${i.name}|${i.family}|${i.address}|${i.netmask}`).toSorted().join("\n");
465
+ }
466
+ function formatKind(kind) {
467
+ switch (kind) {
468
+ case "lan": return "LAN";
469
+ case "wifi": return "Wi-Fi";
470
+ case "vpn": return "VPN";
471
+ case "docker": return "Docker";
472
+ case "loopback": return "Loopback";
473
+ case "other": return "Other";
474
+ }
475
+ }
476
+ //#endregion
477
+ export { LocalNetworkAddon, applyAllowlist, autoSeedAllowlist, buildEndpoints, classifyKind, enumerateOsInterfaces, explainNonPlausible, isPlausibleAutoSeed, pickPreferred, prefixLen };
@@ -0,0 +1,2 @@
1
+ export { default as NativeMetricsAddon } from './native-metrics.addon.js';
2
+ export { NativeMetricsProvider } from './native-metrics-provider.js';
@@ -0,0 +1,48 @@
1
+ import { SystemResourceSnapshot, MemoryInfo, DiskSpaceInfo, MetricsGpuInfo, PidResourceStats } from '@camstack/types';
2
+ interface SamplingDiagnostics {
3
+ warn(message: string, meta?: Record<string, unknown>): void;
4
+ }
5
+ export declare class NativeMetricsProvider {
6
+ readonly id = "native";
7
+ private cachedSnapshot;
8
+ private samplingTimer;
9
+ private macMemTimer;
10
+ private prevCpu;
11
+ private diagnostics;
12
+ private consecutiveSampleErrors;
13
+ constructor();
14
+ /**
15
+ * Optional diagnostics sink for sampling errors. The first failure and
16
+ * every Nth failure thereafter are reported so a permanently-broken
17
+ * collector doesn't spam logs but is still observable.
18
+ */
19
+ setDiagnostics(diag: SamplingDiagnostics): void;
20
+ startSampling(intervalMs: number): void;
21
+ private reportSampleError;
22
+ stopSampling(): void;
23
+ collectSnapshot(): Promise<SystemResourceSnapshot>;
24
+ getCached(): Promise<SystemResourceSnapshot | null>;
25
+ getCurrent(): Promise<{
26
+ cpuPercent: number;
27
+ memoryPercent: number;
28
+ memoryUsedMB: number;
29
+ memoryTotalMB: number;
30
+ diskPercent?: number;
31
+ temperature?: number;
32
+ gpuPercent?: number;
33
+ gpuMemoryPercent?: number;
34
+ }>;
35
+ getDiskSpace(input: {
36
+ dirPath: string;
37
+ }): Promise<DiskSpaceInfo>;
38
+ getGpuInfo(): Promise<MetricsGpuInfo | null>;
39
+ getCpuTemperature(): Promise<number | null>;
40
+ getProcessStats(input: {
41
+ pids: number[];
42
+ }): Promise<PidResourceStats[]>;
43
+ private sampleCpu;
44
+ /** Cached macOS memory (set by sampleMacMemory timer). */
45
+ _cachedMacMem: MemoryInfo | null;
46
+ private getMemoryInfo;
47
+ }
48
+ export {};
@@ -0,0 +1,73 @@
1
+ import { ProviderRegistration, BaseAddon } from '@camstack/types';
2
+ interface NativeMetricsConfig {
3
+ readonly samplingIntervalMs: number;
4
+ }
5
+ /**
6
+ * Native metrics — CPU, memory, disk usage sampling.
7
+ * Settings appear under Cluster → NodeDetail → Settings.
8
+ */
9
+ export default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
10
+ private provider;
11
+ private startedAtMs;
12
+ private snapshotTimer;
13
+ /**
14
+ * Snapshot-equality cache for the resources + processes emit.
15
+ * Stores the coarsened JSON and timestamp; a tick where the
16
+ * coarsened payload matches the cache (and the heartbeat hasn't
17
+ * elapsed) is skipped.
18
+ */
19
+ private lastResourcesEmit;
20
+ private lastProcessesEmit;
21
+ constructor();
22
+ protected onInitialize(): Promise<ProviderRegistration[]>;
23
+ protected onShutdown(): Promise<void>;
24
+ /**
25
+ * Emit one `metrics.node-resources-snapshot` + one
26
+ * `metrics.node-processes-snapshot` for this node. UI consumers
27
+ * subscribe and read state directly from the payload.
28
+ */
29
+ private emitMetricsSnapshots;
30
+ protected onConfigChanged(): Promise<void>;
31
+ private listWorkerInstances;
32
+ private listAddonInstances;
33
+ private getAddonStats;
34
+ /**
35
+ * Walk the OS process table and classify each camstack-shaped process.
36
+ *
37
+ * Classification (ancestry-driven, NOT pattern-driven):
38
+ * - root — the current node's own pid (`process.pid`).
39
+ * - managed — pid is registered in the kernel's `$process.list`
40
+ * (forked addon worker spawned by this hub).
41
+ * - system — ancestry walk crosses a SUPERVISOR_BOUNDARY_RE match
42
+ * (tsx-watch launcher, agent CLI, concurrently, vite,
43
+ * npm exec wrapper). The process belongs to the dev
44
+ * tree even if not in `$process.list`. NEVER killable.
45
+ * - ghost — ancestry walk reaches `ppid=1` without crossing any
46
+ * supervisor boundary AND the parent isn't visible in
47
+ * `ps`. A truly orphaned camstack-shaped process. The
48
+ * ONLY classification that's eligible for kill.
49
+ *
50
+ * Old pattern-only ghost detection produced false positives: every
51
+ * monorepo-path process matched CAMSTACK_CMD_RE, ancestry walk
52
+ * stopping at ppid=hub returned false-positive ghosts whenever a
53
+ * concurrently sibling sat above hub. Ancestry-driven classification
54
+ * fixes that.
55
+ */
56
+ private listNodeProcesses;
57
+ /**
58
+ * Send SIGTERM / SIGKILL to a pid. Refuses pids that don't appear in
59
+ * `listNodeProcesses()` to prevent arbitrary system kills — a dedicated
60
+ * admin-path for resurrected zombies, not a generic shell replacement.
61
+ *
62
+ * `root`-classified pids (the running launcher / agent CLI / hub itself)
63
+ * are also refused: killing them tears down the whole node and the
64
+ * operator's intent is almost always to nuke a leaked child, not the
65
+ * supervisor that keeps the rest alive. Process restart goes through
66
+ * the dedicated `$process.restart` action, not this kill API.
67
+ */
68
+ private killProcess;
69
+ /** Raw `ps` scan returning every pid + command + resource stats. */
70
+ private runPs;
71
+ protected globalSettingsSchema(): import('@camstack/types').ConfigUISchema;
72
+ }
73
+ export {};