@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,822 @@
1
+ import * as fs from "node:fs";
2
+ import { BaseAddon, EventCategory, errMsg, platformProbeCapability } from "@camstack/types";
3
+ import { execFile } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+ import * as os from "node:os";
6
+ //#region src/builtins/platform-probe/platform-scorer.ts
7
+ /**
8
+ * Promisified `execFile`. Used across the scorer so every subprocess
9
+ * spawn yields the event loop — critical at boot because a single sync
10
+ * spawn of a missing Python module hits its 30s timeout and freezes the
11
+ * entire Node process (WS handshakes, tRPC subscriptions, metrics — all
12
+ * stalled). Keeping it async turns the probe into a true background task.
13
+ */
14
+ var execFileAsync$2 = promisify(execFile);
15
+ /** Minimal no-op logger for default parameter */
16
+ var noopLogger = {
17
+ debug() {},
18
+ info() {},
19
+ warn() {},
20
+ error() {},
21
+ child() {
22
+ return noopLogger;
23
+ },
24
+ withTags() {
25
+ return noopLogger;
26
+ }
27
+ };
28
+ /**
29
+ * Get reliable "available" RAM in MB, cross-platform.
30
+ * os.freemem() is unreliable on macOS (reports ~200MB on a 36GB system).
31
+ * Uses systeminformation when available, falls back to native commands.
32
+ */
33
+ async function getAvailableRAM_MB() {
34
+ try {
35
+ const mem = await (await import("systeminformation")).mem();
36
+ return Math.round(mem.available / 1024 / 1024);
37
+ } catch (err) {
38
+ console.debug(`systeminformation not available, using platform-specific RAM probe: ${errMsg(err)}`);
39
+ const platform = os.platform();
40
+ try {
41
+ if (platform === "darwin") {
42
+ const { stdout: output } = await execFileAsync$2("vm_stat", [], {
43
+ encoding: "utf8",
44
+ timeout: 3e3
45
+ });
46
+ const pageSize = parseInt(output.match(/page size of (\d+)/)?.[1] ?? "16384");
47
+ const free = parseInt(output.match(/Pages free:\s+(\d+)/)?.[1] ?? "0");
48
+ const inactive = parseInt(output.match(/Pages inactive:\s+(\d+)/)?.[1] ?? "0");
49
+ const purgeable = parseInt(output.match(/Pages purgeable:\s+(\d+)/)?.[1] ?? "0");
50
+ return Math.round((free + inactive + purgeable) * pageSize / 1024 / 1024);
51
+ } else if (platform === "linux") {
52
+ const { readFileSync } = await import("node:fs");
53
+ const match = readFileSync("/proc/meminfo", "utf8").match(/MemAvailable:\s+(\d+)\s+kB/);
54
+ if (match) return Math.round(parseInt(match[1]) / 1024);
55
+ }
56
+ } catch (err) {
57
+ console.debug(`RAM probe failed, using total RAM fallback: ${errMsg(err)}`);
58
+ }
59
+ return Math.round(os.totalmem() / 1024 / 1024);
60
+ }
61
+ }
62
+ var PlatformScorer = class {
63
+ cached = null;
64
+ logger;
65
+ /**
66
+ * Path to the embedded portable Python (from `ctx.deps.ensurePython()`).
67
+ * The Docker hub ships NO system `python3` — inference runs on the
68
+ * downloaded portable build — so probing system `python3`/`python` would
69
+ * wrongly report "Python not found" and never surface coreml/openvino
70
+ * backends. When set, the Python module probes run against THIS binary;
71
+ * `null` falls back to a system `python3`/`python` lookup (dev / agent
72
+ * environments where Python is on PATH).
73
+ */
74
+ embeddedPythonPath;
75
+ constructor(logger = noopLogger, embeddedPythonPath = null) {
76
+ this.logger = logger;
77
+ this.embeddedPythonPath = embeddedPythonPath;
78
+ }
79
+ /**
80
+ * Probe hardware + runtimes and score all backend combos.
81
+ *
82
+ * An optional `onPhase` callback is invoked at each step so consumers
83
+ * (e.g. the platform-probe addon) can emit live progress events on
84
+ * the event bus. The callback takes a phase id + a typed payload; all
85
+ * phases fire in strict order: `started` → `hardware` → `node-backends`
86
+ * → `python-backends` → `scored` → `done`. On failure, `error` fires
87
+ * once with the exception. Cached after first call.
88
+ */
89
+ async probe(onPhase) {
90
+ if (this.cached) return this.cached;
91
+ const start = Date.now();
92
+ onPhase?.("started", {});
93
+ this.logger.info("Probing hardware...");
94
+ const hardware = await this.probeHardware();
95
+ this.logger.info("Hardware detected", { meta: {
96
+ platform: hardware.platform,
97
+ arch: hardware.arch,
98
+ cpuModel: hardware.cpuModel,
99
+ cpuCores: hardware.cpuCores,
100
+ ramGB: Math.round(hardware.totalRAM_MB / 1024)
101
+ } });
102
+ if (hardware.gpu) this.logger.info("GPU detected", { meta: { name: hardware.gpu.name } });
103
+ if (hardware.npu) this.logger.info("NPU detected", { meta: { type: hardware.npu.type } });
104
+ onPhase?.("hardware", { hardware });
105
+ this.logger.info("Probing Python backends...");
106
+ const pythonInfo = await this.probePythonBackends();
107
+ if (pythonInfo.pythonPath) this.logger.info("Python backends detected", { meta: {
108
+ pythonPath: pythonInfo.pythonPath,
109
+ backends: pythonInfo.backends.filter((b) => b.available).map((b) => b.id)
110
+ } });
111
+ else this.logger.info("Python: not found");
112
+ onPhase?.("python-backends", {
113
+ pythonPath: pythonInfo.pythonPath,
114
+ backends: pythonInfo.backends
115
+ });
116
+ const scores = this.scoreBackends(hardware, pythonInfo.backends);
117
+ const bestScore = scores.find((s) => s.available) ?? scores[scores.length - 1];
118
+ const elapsed = Date.now() - start;
119
+ this.logger.info("Scoring complete", { meta: {
120
+ elapsedMs: elapsed,
121
+ combos: scores.length
122
+ } });
123
+ this.logger.info("Best backend selected", { meta: {
124
+ runtime: bestScore.runtime,
125
+ backend: bestScore.backend,
126
+ format: bestScore.format,
127
+ reason: bestScore.reason,
128
+ score: bestScore.score
129
+ } });
130
+ for (const s of scores) this.logger.debug("Score entry", { meta: {
131
+ available: s.available,
132
+ runtime: s.runtime,
133
+ backend: s.backend,
134
+ format: s.format,
135
+ score: s.score,
136
+ reason: s.reason
137
+ } });
138
+ this.cached = {
139
+ hardware,
140
+ scores,
141
+ bestScore,
142
+ pythonPath: pythonInfo.pythonPath
143
+ };
144
+ onPhase?.("scored", {
145
+ scores,
146
+ bestScore,
147
+ elapsedMs: elapsed
148
+ });
149
+ onPhase?.("done", { capabilities: this.cached });
150
+ return this.cached;
151
+ }
152
+ async probeHardware() {
153
+ const platform = os.platform();
154
+ const arch = os.arch();
155
+ const cpus = os.cpus();
156
+ const cpuModel = cpus[0]?.model ?? "unknown";
157
+ const cpuCores = cpus.length;
158
+ const totalRAM_MB = Math.round(os.totalmem() / 1024 / 1024);
159
+ const availableRAM_MB = await getAvailableRAM_MB();
160
+ this.logger.debug("RAM probed", { meta: {
161
+ totalRAM_MB,
162
+ availableRAM_MB
163
+ } });
164
+ let gpu = null;
165
+ let npu = null;
166
+ if (platform === "darwin" && arch === "arm64") {
167
+ gpu = {
168
+ type: "apple",
169
+ name: "Apple Silicon GPU"
170
+ };
171
+ npu = { type: "apple-ane" };
172
+ }
173
+ if (platform === "linux") {
174
+ try {
175
+ const { stdout } = await execFileAsync$2("nvidia-smi", ["--query-gpu=name,memory.total", "--format=csv,noheader"], {
176
+ encoding: "utf8",
177
+ timeout: 5e3
178
+ });
179
+ const output = stdout.trim();
180
+ if (output) {
181
+ const [name, mem] = output.split(",").map((s) => s.trim());
182
+ gpu = {
183
+ type: "nvidia",
184
+ name: name ?? "NVIDIA GPU",
185
+ memoryMB: parseInt(mem ?? "0")
186
+ };
187
+ }
188
+ } catch (err) {
189
+ this.logger.debug("NVIDIA GPU detection failed", { meta: { error: errMsg(err) } });
190
+ }
191
+ if (!gpu || !npu) {
192
+ const { classifyIntelAccelerators } = await import("../../intel-accelerators-hGgpZ0pX.mjs");
193
+ const intel = classifyIntelAccelerators({
194
+ listRenderNodes: () => {
195
+ try {
196
+ return fs.readdirSync("/dev/dri").filter((n) => n.startsWith("renderD")).map((n) => `/dev/dri/${n}`);
197
+ } catch {
198
+ return [];
199
+ }
200
+ },
201
+ readVendor: (node) => {
202
+ try {
203
+ return fs.readFileSync(`/sys/class/drm/${node.split("/").pop()}/device/vendor`, "utf8");
204
+ } catch {
205
+ return "";
206
+ }
207
+ },
208
+ exists: (p) => fs.existsSync(p)
209
+ });
210
+ gpu = gpu ?? intel.gpu;
211
+ npu = npu ?? intel.npu;
212
+ if (intel.npu) this.logger.info("Intel NPU detected", { meta: { device: "/dev/accel/accel0" } });
213
+ if (intel.gpu) this.logger.info("Intel iGPU detected", { meta: { name: intel.gpu.name } });
214
+ }
215
+ }
216
+ return {
217
+ platform,
218
+ arch,
219
+ cpuModel,
220
+ cpuCores,
221
+ totalRAM_MB,
222
+ availableRAM_MB,
223
+ gpu,
224
+ npu
225
+ };
226
+ }
227
+ async probePythonBackends() {
228
+ const candidates = [
229
+ ...this.embeddedPythonPath ? [this.embeddedPythonPath] : [],
230
+ "python3",
231
+ "python"
232
+ ];
233
+ let pythonPath = null;
234
+ for (const cmd of candidates) try {
235
+ await execFileAsync$2(cmd, ["--version"], { timeout: 5e3 });
236
+ pythonPath = cmd;
237
+ break;
238
+ } catch (err) {
239
+ console.debug(`Python command "${cmd}" not found: ${errMsg(err)}`);
240
+ }
241
+ if (!pythonPath) return {
242
+ pythonPath: null,
243
+ backends: []
244
+ };
245
+ const results = await Promise.all([
246
+ [
247
+ "coremltools",
248
+ "coreml",
249
+ "coreml"
250
+ ],
251
+ [
252
+ "openvino.runtime",
253
+ "openvino",
254
+ "openvino"
255
+ ],
256
+ [
257
+ "torch",
258
+ "pytorch",
259
+ "onnx"
260
+ ],
261
+ [
262
+ "onnxruntime",
263
+ "onnx-py",
264
+ "onnx"
265
+ ]
266
+ ].map(async ([mod, id, format]) => {
267
+ const probeStart = Date.now();
268
+ let available = false;
269
+ try {
270
+ await execFileAsync$2(pythonPath, ["-c", `import ${mod}`], { timeout: 3e4 });
271
+ available = true;
272
+ this.logger.info("Python backend confirmed", { meta: {
273
+ backend: id,
274
+ module: mod
275
+ } });
276
+ } catch (err) {
277
+ console.debug(`Python module "${mod}" not installed: ${errMsg(err)}`);
278
+ if (id === "openvino") this.logger.info("Python backend not yet confirmed: openvino (may be pending proactive install on Intel hardware — falling back to onnx-cpu)", { meta: { module: mod } });
279
+ }
280
+ const probeMs = Date.now() - probeStart;
281
+ this.logger.debug("Python module probed", { meta: {
282
+ module: mod,
283
+ available,
284
+ probeMs
285
+ } });
286
+ return {
287
+ mod,
288
+ id,
289
+ format,
290
+ available
291
+ };
292
+ }));
293
+ const backends = [];
294
+ for (const r of results) if (r.id === "coreml" && os.platform() === "darwin") backends.push({
295
+ id: r.id,
296
+ format: r.format,
297
+ available: r.available
298
+ });
299
+ else if (r.available) backends.push({
300
+ id: r.id,
301
+ format: r.format,
302
+ available: r.available
303
+ });
304
+ return {
305
+ pythonPath,
306
+ backends
307
+ };
308
+ }
309
+ scoreBackends(hardware, pythonBackends) {
310
+ const scores = [];
311
+ if (hardware.platform === "darwin" && hardware.arch === "arm64") {
312
+ const pyCoreMl = pythonBackends.find((b) => b.id === "coreml");
313
+ if (pyCoreMl) scores.push({
314
+ runtime: "python",
315
+ backend: "coreml",
316
+ format: "coreml",
317
+ score: 95,
318
+ reason: "Apple Neural Engine (Python CoreML)",
319
+ available: pyCoreMl.available
320
+ });
321
+ }
322
+ if (hardware.gpu?.type === "nvidia") scores.push({
323
+ runtime: "python",
324
+ backend: "cuda",
325
+ format: "onnx",
326
+ score: 85,
327
+ reason: "NVIDIA CUDA (Python ONNX Runtime)",
328
+ available: true
329
+ });
330
+ const openvino = pythonBackends.find((b) => b.id === "openvino");
331
+ if (openvino) {
332
+ const score = hardware.npu?.type === "intel-npu" ? 90 : 80;
333
+ scores.push({
334
+ runtime: "python",
335
+ backend: "openvino",
336
+ format: "openvino",
337
+ score,
338
+ reason: "Intel OpenVINO",
339
+ available: openvino.available
340
+ });
341
+ }
342
+ scores.push({
343
+ runtime: "python",
344
+ backend: "cpu",
345
+ format: "onnx",
346
+ score: 50,
347
+ reason: "CPU (Python ONNX Runtime)",
348
+ available: true
349
+ });
350
+ return scores.toSorted((a, b) => b.score - a.score);
351
+ }
352
+ };
353
+ //#endregion
354
+ //#region src/builtins/platform-probe/inference-config-resolver.ts
355
+ var InferenceConfigResolver = class {
356
+ scores;
357
+ hardware;
358
+ constructor(scores, hardware) {
359
+ this.scores = scores;
360
+ this.hardware = hardware;
361
+ }
362
+ /**
363
+ * Compute accuracy/backend weights based on available system RAM.
364
+ * availableRAM_MB is now sourced from systeminformation (reliable cross-platform),
365
+ * not os.freemem() which is broken on macOS.
366
+ *
367
+ * - > 16 GB available: prefer larger, more accurate models (accuracy 0.6, backend 0.4)
368
+ * - > 8 GB available: balanced (accuracy 0.5, backend 0.5)
369
+ * - <= 8 GB available: prefer speed (accuracy 0.4, backend 0.6)
370
+ */
371
+ getWeights() {
372
+ const ramMB = this.hardware.availableRAM_MB;
373
+ if (ramMB > 16384) return {
374
+ accuracyWeight: .6,
375
+ backendWeight: .4
376
+ };
377
+ if (ramMB > 8192) return {
378
+ accuracyWeight: .5,
379
+ backendWeight: .5
380
+ };
381
+ return {
382
+ accuracyWeight: .4,
383
+ backendWeight: .6
384
+ };
385
+ }
386
+ /**
387
+ * Given an addon's model requirements, pick the best model + runtime + backend.
388
+ *
389
+ * Algorithm:
390
+ * 1. Filter models by available RAM (minRAM_MB < 25% of available RAM)
391
+ * 2. For each remaining model, find the best platform score whose format
392
+ * is available in the model's formats
393
+ * 3. Pick the model with the highest combined score using RAM-adaptive weights:
394
+ * - High RAM (>16 GB): accuracy × 0.6 + backend × 0.4 (prefer accuracy)
395
+ * - Mid RAM (>8 GB): accuracy × 0.5 + backend × 0.5 (balanced)
396
+ * - Low RAM (<=8 GB): accuracy × 0.4 + backend × 0.6 (prefer speed)
397
+ */
398
+ resolve(requirements) {
399
+ if (requirements.length === 0) return {
400
+ modelId: "",
401
+ runtime: "node",
402
+ backend: "cpu",
403
+ format: "onnx",
404
+ reason: "No models declared"
405
+ };
406
+ const ramBudget = this.hardware.availableRAM_MB * .25;
407
+ const { accuracyWeight, backendWeight } = this.getWeights();
408
+ console.log(`[InferenceConfigResolver] availableRAM: ${this.hardware.availableRAM_MB}MB, budget: ${Math.round(ramBudget)}MB, weights: accuracy=${accuracyWeight}, backend=${backendWeight}`);
409
+ const fits = requirements.filter((m) => m.minRAM_MB < ramBudget);
410
+ const candidates = fits.length > 0 ? fits : [requirements[0]];
411
+ console.log(`[InferenceConfigResolver] ${candidates.length}/${requirements.length} models fit RAM budget`);
412
+ let bestCombo = null;
413
+ for (const model of candidates) for (const score of this.scores) {
414
+ if (!score.available) continue;
415
+ if (!model.formats.includes(score.format)) continue;
416
+ const combined = model.accuracyScore * accuracyWeight + score.score * backendWeight;
417
+ if (!bestCombo || combined > bestCombo.combined) {
418
+ console.log(`[InferenceConfigResolver] New best: ${model.modelId} (accuracy=${model.accuracyScore}) + ${score.backend}/${score.format} (score=${score.score}) → combined=${Math.round(combined)}`);
419
+ bestCombo = {
420
+ model,
421
+ score,
422
+ combined
423
+ };
424
+ }
425
+ }
426
+ if (!bestCombo) return {
427
+ modelId: candidates[0].modelId,
428
+ runtime: "node",
429
+ backend: "cpu",
430
+ format: "onnx",
431
+ reason: "No compatible backend — CPU fallback"
432
+ };
433
+ return {
434
+ modelId: bestCombo.model.modelId,
435
+ runtime: bestCombo.score.runtime,
436
+ backend: bestCombo.score.backend,
437
+ format: bestCombo.score.format,
438
+ reason: `${bestCombo.model.name} on ${bestCombo.score.reason} (score: ${Math.round(bestCombo.combined)})`
439
+ };
440
+ }
441
+ };
442
+ //#endregion
443
+ //#region src/builtins/platform-probe/hardware-encoder-probe.ts
444
+ var execFileAsync$1 = promisify(execFile);
445
+ function buildCandidates(hardware) {
446
+ const out = [];
447
+ if (hardware.platform === "darwin") {
448
+ out.push({
449
+ encoder: "h264_videotoolbox",
450
+ codec: "H264",
451
+ family: "videotoolbox"
452
+ });
453
+ out.push({
454
+ encoder: "hevc_videotoolbox",
455
+ codec: "H265",
456
+ family: "videotoolbox"
457
+ });
458
+ }
459
+ if (hardware.platform === "linux") {
460
+ if (hardware.gpu?.type === "nvidia") {
461
+ out.push({
462
+ encoder: "h264_nvenc",
463
+ codec: "H264",
464
+ family: "nvenc"
465
+ });
466
+ out.push({
467
+ encoder: "hevc_nvenc",
468
+ codec: "H265",
469
+ family: "nvenc"
470
+ });
471
+ }
472
+ if (hardware.gpu?.type === "intel" || hardware.gpu?.type === "amd" || !hardware.gpu) {
473
+ out.push({
474
+ encoder: "h264_vaapi",
475
+ codec: "H264",
476
+ family: "vaapi"
477
+ });
478
+ out.push({
479
+ encoder: "hevc_vaapi",
480
+ codec: "H265",
481
+ family: "vaapi"
482
+ });
483
+ }
484
+ }
485
+ return out;
486
+ }
487
+ async function runTestEncode(candidate, opts) {
488
+ const ffmpeg = opts.ffmpegPath ?? "ffmpeg";
489
+ const timeout = opts.timeoutMs ?? 8e3;
490
+ const nullSink = os.platform() === "win32" ? "NUL" : "/dev/null";
491
+ const baseArgs = [
492
+ "-hide_banner",
493
+ "-loglevel",
494
+ "error"
495
+ ];
496
+ const inArgs = [
497
+ "-f",
498
+ "lavfi",
499
+ "-i",
500
+ "testsrc=duration=0.04:size=16x16:rate=25"
501
+ ];
502
+ let outArgs;
503
+ if (candidate.family === "vaapi") outArgs = [
504
+ "-vaapi_device",
505
+ "/dev/dri/renderD128",
506
+ "-vf",
507
+ "format=nv12,hwupload",
508
+ "-c:v",
509
+ candidate.encoder,
510
+ "-frames:v",
511
+ "1",
512
+ "-f",
513
+ "null",
514
+ nullSink
515
+ ];
516
+ else outArgs = [
517
+ "-c:v",
518
+ candidate.encoder,
519
+ "-frames:v",
520
+ "1",
521
+ "-f",
522
+ "null",
523
+ nullSink
524
+ ];
525
+ try {
526
+ await execFileAsync$1(ffmpeg, [
527
+ ...baseArgs,
528
+ ...inArgs,
529
+ ...outArgs
530
+ ], {
531
+ timeout,
532
+ encoding: "utf8"
533
+ });
534
+ return {
535
+ encoder: candidate.encoder,
536
+ codec: candidate.codec,
537
+ family: candidate.family,
538
+ available: true
539
+ };
540
+ } catch (err) {
541
+ return {
542
+ encoder: candidate.encoder,
543
+ codec: candidate.codec,
544
+ family: candidate.family,
545
+ available: false,
546
+ reason: errMsg(err)
547
+ };
548
+ }
549
+ }
550
+ var HardwareEncoderProber = class {
551
+ cached = null;
552
+ inflight = null;
553
+ logger;
554
+ ffmpegPath;
555
+ constructor(logger, ffmpegPath = "ffmpeg") {
556
+ this.logger = logger;
557
+ this.ffmpegPath = ffmpegPath;
558
+ }
559
+ getCached() {
560
+ return this.cached;
561
+ }
562
+ async probe(hardware, options = {}) {
563
+ if (!options.force && this.cached) return this.cached;
564
+ if (this.inflight) return this.inflight;
565
+ this.inflight = this.runProbe(hardware).then((res) => {
566
+ this.cached = res;
567
+ this.inflight = null;
568
+ return res;
569
+ }).catch((err) => {
570
+ this.inflight = null;
571
+ throw err;
572
+ });
573
+ return this.inflight;
574
+ }
575
+ async runProbe(hardware) {
576
+ const candidates = buildCandidates(hardware);
577
+ const start = Date.now();
578
+ this.logger.info("Probing hardware encoders", { meta: {
579
+ platform: hardware.platform,
580
+ arch: hardware.arch,
581
+ candidates: candidates.length
582
+ } });
583
+ const probes = await Promise.all(candidates.map((c) => runTestEncode(c, { ffmpegPath: this.ffmpegPath })));
584
+ probes.push({
585
+ encoder: "libx264",
586
+ codec: "H264",
587
+ family: "software",
588
+ available: true
589
+ });
590
+ probes.push({
591
+ encoder: "libx265",
592
+ codec: "H265",
593
+ family: "software",
594
+ available: true
595
+ });
596
+ const pickDefault = (codec) => {
597
+ const hw = probes.find((p) => p.codec === codec && p.available && p.family !== "software");
598
+ if (hw) return hw.encoder;
599
+ return codec === "H264" ? "libx264" : "libx265";
600
+ };
601
+ const result = {
602
+ encoders: probes,
603
+ defaultH264: pickDefault("H264"),
604
+ defaultH265: pickDefault("H265"),
605
+ probedAt: Date.now()
606
+ };
607
+ const elapsed = Date.now() - start;
608
+ this.logger.info("Hardware encoder probe complete", { meta: {
609
+ elapsedMs: elapsed,
610
+ defaultH264: result.defaultH264,
611
+ defaultH265: result.defaultH265,
612
+ availableHw: probes.filter((p) => p.available && p.family !== "software").map((p) => p.encoder)
613
+ } });
614
+ return result;
615
+ }
616
+ };
617
+ //#endregion
618
+ //#region src/builtins/platform-probe/hardware-decode-accel-probe.ts
619
+ var execFileAsync = promisify(execFile);
620
+ var defaultExecFn = async (ffmpegPath, args) => {
621
+ const { stdout } = await execFileAsync(ffmpegPath, [...args], {
622
+ timeout: 8e3,
623
+ encoding: "utf8"
624
+ });
625
+ return { stdout };
626
+ };
627
+ /**
628
+ * Parse the output of `ffmpeg -hwaccels`. The listing looks like:
629
+ *
630
+ * Hardware acceleration methods:
631
+ * videotoolbox
632
+ *
633
+ * The header line is dropped; remaining non-empty trimmed lines are the
634
+ * method names, lowercased and de-duplicated (order preserved).
635
+ */
636
+ function parseHwAccelsOutput(stdout) {
637
+ const seen = /* @__PURE__ */ new Set();
638
+ const methods = [];
639
+ for (const raw of stdout.split("\n")) {
640
+ const line = raw.trim().toLowerCase();
641
+ if (line.length === 0) continue;
642
+ if (line.endsWith("methods:")) continue;
643
+ if (seen.has(line)) continue;
644
+ seen.add(line);
645
+ methods.push(line);
646
+ }
647
+ return methods;
648
+ }
649
+ /**
650
+ * Probes which `-hwaccel` decode backends the configured ffmpeg binary
651
+ * supports. Mirrors {@link HardwareEncoderProber} (configured binary, cached,
652
+ * single-flight, forceable). Never throws: a probe failure yields an empty
653
+ * method list so callers fall back to software decode.
654
+ */
655
+ var HardwareDecodeAccelProber = class {
656
+ cached = null;
657
+ inflight = null;
658
+ logger;
659
+ ffmpegPath;
660
+ execFn;
661
+ constructor(logger, ffmpegPath = "ffmpeg", execFn = defaultExecFn) {
662
+ this.logger = logger;
663
+ this.ffmpegPath = ffmpegPath;
664
+ this.execFn = execFn;
665
+ }
666
+ getCached() {
667
+ return this.cached;
668
+ }
669
+ async probe(options = {}) {
670
+ if (!options.force && this.cached) return this.cached;
671
+ if (this.inflight) return this.inflight;
672
+ this.inflight = this.runProbe().then((res) => {
673
+ this.cached = res;
674
+ this.inflight = null;
675
+ return res;
676
+ }).catch((err) => {
677
+ this.inflight = null;
678
+ throw err;
679
+ });
680
+ return this.inflight;
681
+ }
682
+ async runProbe() {
683
+ try {
684
+ const { stdout } = await this.execFn(this.ffmpegPath, ["-hide_banner", "-hwaccels"]);
685
+ const methods = parseHwAccelsOutput(stdout);
686
+ this.logger.info("Hardware decode-accel probe complete", { meta: { methods } });
687
+ return {
688
+ methods,
689
+ probedAt: Date.now()
690
+ };
691
+ } catch (err) {
692
+ this.logger.warn("Hardware decode-accel probe failed — assuming none available", { meta: { error: errMsg(err) } });
693
+ return {
694
+ methods: [],
695
+ probedAt: Date.now()
696
+ };
697
+ }
698
+ }
699
+ };
700
+ //#endregion
701
+ //#region src/builtins/platform-probe/index.ts
702
+ var PlatformProbeNativeAddon = class extends BaseAddon {
703
+ scorer = null;
704
+ encoderProber = null;
705
+ decodeAccelProber = null;
706
+ cachedCaps = null;
707
+ constructor() {
708
+ super({});
709
+ }
710
+ /**
711
+ * Resolve the ffmpeg binary the encoder probe should test, from the cluster
712
+ * `ffmpeg` config section (`binaryPath`). The probe MUST exercise the same
713
+ * binary the broker/recorder spawn, or it may report encoders for a different
714
+ * ffmpeg. Defaults to PATH `ffmpeg` on any miss.
715
+ */
716
+ async resolveFfmpegBinaryPath() {
717
+ try {
718
+ const bp = (await this.ctx.settings?.getSection("ffmpeg") ?? {})["binaryPath"];
719
+ return typeof bp === "string" && bp.trim().length > 0 ? bp : "ffmpeg";
720
+ } catch {
721
+ return "ffmpeg";
722
+ }
723
+ }
724
+ async onInitialize() {
725
+ const embeddedPython = await this.ctx.deps.ensurePython().catch((err) => {
726
+ this.ctx.logger.debug("ensurePython unavailable for platform probe", { meta: { error: errMsg(err) } });
727
+ return null;
728
+ });
729
+ this.scorer = new PlatformScorer(this.ctx.logger, embeddedPython);
730
+ const ffmpegPath = await this.resolveFfmpegBinaryPath();
731
+ this.encoderProber = new HardwareEncoderProber(this.ctx.logger, ffmpegPath);
732
+ this.decodeAccelProber = new HardwareDecodeAccelProber(this.ctx.logger, ffmpegPath);
733
+ const emitPhase = (phase, payload) => {
734
+ this.ctx.eventBus?.emit({
735
+ id: `platform-probe-${phase}-${Date.now()}`,
736
+ timestamp: /* @__PURE__ */ new Date(),
737
+ source: {
738
+ type: "core",
739
+ id: "platform-probe-native"
740
+ },
741
+ category: EventCategory.PlatformProbePhase,
742
+ data: {
743
+ type: "platform-probe.phase",
744
+ phase,
745
+ ...payload
746
+ }
747
+ });
748
+ };
749
+ const probePromise = this.scorer.probe(emitPhase).then((caps) => {
750
+ this.cachedCaps = caps;
751
+ this.ctx.logger.info("Platform probe complete", { meta: {
752
+ cpuModel: caps.hardware.cpuModel,
753
+ arch: caps.hardware.arch,
754
+ totalRAM_MB: caps.hardware.totalRAM_MB,
755
+ gpu: caps.hardware.gpu?.name ?? "none",
756
+ bestReason: caps.bestScore.reason,
757
+ bestScore: caps.bestScore.score
758
+ } });
759
+ return caps;
760
+ }).catch((err) => {
761
+ const msg = errMsg(err);
762
+ this.ctx.logger.error("Platform probe failed", { meta: { error: msg } });
763
+ emitPhase("error", { message: msg });
764
+ throw err;
765
+ });
766
+ const getCaps = async () => {
767
+ return this.cachedCaps ?? probePromise;
768
+ };
769
+ return [{
770
+ capability: platformProbeCapability,
771
+ provider: {
772
+ getCapabilities: async () => {
773
+ return getCaps();
774
+ },
775
+ getHardware: async () => {
776
+ return (await getCaps()).hardware;
777
+ },
778
+ resolveInferenceConfig: async (input) => {
779
+ const caps = await getCaps();
780
+ return new InferenceConfigResolver(caps.scores, caps.hardware).resolve(input.requirements);
781
+ },
782
+ resolveHwAccel: async (input) => {
783
+ const hwaccel = this.ctx.kernel.hwaccel;
784
+ if (!hwaccel) return { preferred: [] };
785
+ return { preferred: (await hwaccel.resolve(input.prefer ?? null)).preferred };
786
+ },
787
+ getHardwareEncoders: async () => {
788
+ const prober = this.encoderProber;
789
+ if (!prober) throw new Error("Hardware encoder prober not initialized");
790
+ const cached = prober.getCached();
791
+ if (cached) return cached;
792
+ const caps = await getCaps();
793
+ return prober.probe(caps.hardware);
794
+ },
795
+ refreshHardwareEncoders: async () => {
796
+ const prober = this.encoderProber;
797
+ if (!prober) throw new Error("Hardware encoder prober not initialized");
798
+ const caps = await getCaps();
799
+ return prober.probe(caps.hardware, { force: true });
800
+ },
801
+ getHardwareDecodeAccels: async () => {
802
+ const prober = this.decodeAccelProber;
803
+ if (!prober) throw new Error("Hardware decode-accel prober not initialized");
804
+ return prober.probe();
805
+ },
806
+ refreshHardwareDecodeAccels: async () => {
807
+ const prober = this.decodeAccelProber;
808
+ if (!prober) throw new Error("Hardware decode-accel prober not initialized");
809
+ return prober.probe({ force: true });
810
+ }
811
+ }
812
+ }];
813
+ }
814
+ async onShutdown() {
815
+ this.scorer = null;
816
+ this.encoderProber = null;
817
+ this.decodeAccelProber = null;
818
+ this.cachedCaps = null;
819
+ }
820
+ };
821
+ //#endregion
822
+ export { HardwareDecodeAccelProber, HardwareEncoderProber, InferenceConfigResolver, PlatformProbeNativeAddon, PlatformProbeNativeAddon as default, PlatformScorer };