@trillboards/edge-sdk 0.2.4 → 0.2.7

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 (204) hide show
  1. package/README.md +4 -3
  2. package/deploy/docker/Dockerfile.cloud-sense +117 -0
  3. package/deploy/docker/Dockerfile.cpu +30 -21
  4. package/deploy/docker/Dockerfile.cuda +30 -21
  5. package/deploy/docker/Dockerfile.openvino +30 -20
  6. package/deploy/docker/README.md +9 -5
  7. package/deploy/docker/connector-entrypoint.sh +122 -0
  8. package/deploy/helm/README.md +1 -1
  9. package/deploy/k8s/daemonset.yaml +1 -1
  10. package/deploy/macos/README.md +161 -0
  11. package/deploy/macos/TrillboardsSetupApp.m +603 -0
  12. package/deploy/macos/build-macos-pkg.sh +588 -0
  13. package/deploy/macos/com.trillboards.edge.plist +62 -0
  14. package/deploy/macos/com.trillboards.litertlm.plist +45 -0
  15. package/deploy/macos/pair.command +519 -0
  16. package/deploy/macos/scripts/ensure-litertlm.sh +62 -0
  17. package/deploy/macos/scripts/postinstall +153 -0
  18. package/deploy/macos/scripts/setup-litertlm.sh +272 -0
  19. package/deploy/macos/test-install-pair.sh +383 -0
  20. package/deploy/macos/test-setup-litertlm-reinstall.sh +109 -0
  21. package/deploy/systemd/install.sh +25 -15
  22. package/deploy/systemd/trillboards-edge.service +4 -1
  23. package/deploy/windows/README.md +70 -0
  24. package/deploy/windows/build-windows.ps1 +225 -0
  25. package/deploy/windows/bundle-windows-installer.ps1 +153 -0
  26. package/deploy/windows/check-feeds.js +26 -0
  27. package/deploy/windows/e2e/fixtures/person.jpg +0 -0
  28. package/deploy/windows/e2e/test-local-sense.ps1 +185 -0
  29. package/deploy/windows/install-service.ps1 +6 -1
  30. package/deploy/windows/install-update.ps1 +101 -0
  31. package/deploy/windows/installer.nsi +138 -0
  32. package/deploy/windows/register-litertlm-task.ps1 +42 -0
  33. package/deploy/windows/register-task.ps1 +44 -0
  34. package/deploy/windows/run-connector.ps1 +69 -0
  35. package/deploy/windows/setup-litertlm.ps1 +361 -0
  36. package/deploy/windows/stop-existing.ps1 +72 -0
  37. package/deploy/windows/trillboards-edge-task.vbs +25 -0
  38. package/deploy/windows/trillboards-edge.cmd +33 -0
  39. package/deploy/windows/trillboards-pair.cmd +276 -0
  40. package/deploy/windows/trillboards-setup.ps1 +456 -0
  41. package/deploy/windows/trillboards-setup.vbs +13 -0
  42. package/dist/AudienceAnalyzeClient.d.ts +136 -0
  43. package/dist/AudienceAnalyzeClient.d.ts.map +1 -0
  44. package/dist/AudienceAnalyzeClient.js +246 -0
  45. package/dist/AudienceAnalyzeClient.js.map +1 -0
  46. package/dist/ChannelProber.d.ts +150 -0
  47. package/dist/ChannelProber.d.ts.map +1 -0
  48. package/dist/ChannelProber.js +887 -0
  49. package/dist/ChannelProber.js.map +1 -0
  50. package/dist/CloudEscalationPolicy.d.ts +143 -0
  51. package/dist/CloudEscalationPolicy.d.ts.map +1 -0
  52. package/dist/CloudEscalationPolicy.js +137 -0
  53. package/dist/CloudEscalationPolicy.js.map +1 -0
  54. package/dist/CloudSensingManager.d.ts +557 -0
  55. package/dist/CloudSensingManager.d.ts.map +1 -0
  56. package/dist/CloudSensingManager.js +1267 -0
  57. package/dist/CloudSensingManager.js.map +1 -0
  58. package/dist/DiscoveryReportClient.d.ts +66 -0
  59. package/dist/DiscoveryReportClient.d.ts.map +1 -0
  60. package/dist/DiscoveryReportClient.js +85 -0
  61. package/dist/DiscoveryReportClient.js.map +1 -0
  62. package/dist/EdgeAgent.d.ts +12 -2
  63. package/dist/EdgeAgent.d.ts.map +1 -1
  64. package/dist/EdgeAgent.js +55 -13
  65. package/dist/EdgeAgent.js.map +1 -1
  66. package/dist/LiteRtVlmProvider.d.ts +193 -0
  67. package/dist/LiteRtVlmProvider.d.ts.map +1 -0
  68. package/dist/LiteRtVlmProvider.js +436 -0
  69. package/dist/LiteRtVlmProvider.js.map +1 -0
  70. package/dist/MosaicSource.d.ts +108 -0
  71. package/dist/MosaicSource.d.ts.map +1 -0
  72. package/dist/MosaicSource.js +274 -0
  73. package/dist/MosaicSource.js.map +1 -0
  74. package/dist/OnvifClient.d.ts +83 -0
  75. package/dist/OnvifClient.d.ts.map +1 -0
  76. package/dist/OnvifClient.js +209 -0
  77. package/dist/OnvifClient.js.map +1 -0
  78. package/dist/PairClient.d.ts +106 -0
  79. package/dist/PairClient.d.ts.map +1 -0
  80. package/dist/PairClient.js +186 -0
  81. package/dist/PairClient.js.map +1 -0
  82. package/dist/RecorderAddressRecovery.d.ts +53 -0
  83. package/dist/RecorderAddressRecovery.d.ts.map +1 -0
  84. package/dist/RecorderAddressRecovery.js +359 -0
  85. package/dist/RecorderAddressRecovery.js.map +1 -0
  86. package/dist/SceneChangeDetector.d.ts +291 -0
  87. package/dist/SceneChangeDetector.d.ts.map +1 -0
  88. package/dist/SceneChangeDetector.js +682 -0
  89. package/dist/SceneChangeDetector.js.map +1 -0
  90. package/dist/SensingProfileClient.d.ts +59 -0
  91. package/dist/SensingProfileClient.d.ts.map +1 -0
  92. package/dist/SensingProfileClient.js +78 -0
  93. package/dist/SensingProfileClient.js.map +1 -0
  94. package/dist/SetupSessionClient.d.ts +114 -0
  95. package/dist/SetupSessionClient.d.ts.map +1 -0
  96. package/dist/SetupSessionClient.js +95 -0
  97. package/dist/SetupSessionClient.js.map +1 -0
  98. package/dist/VlmAdmissionGate.d.ts +126 -0
  99. package/dist/VlmAdmissionGate.d.ts.map +1 -0
  100. package/dist/VlmAdmissionGate.js +166 -0
  101. package/dist/VlmAdmissionGate.js.map +1 -0
  102. package/dist/autoSense.d.ts +266 -0
  103. package/dist/autoSense.d.ts.map +1 -0
  104. package/dist/autoSense.js +606 -0
  105. package/dist/autoSense.js.map +1 -0
  106. package/dist/cli.d.ts +27 -1
  107. package/dist/cli.d.ts.map +1 -1
  108. package/dist/cli.js +526 -27
  109. package/dist/cli.js.map +1 -1
  110. package/dist/combinedSense.d.ts +128 -0
  111. package/dist/combinedSense.d.ts.map +1 -0
  112. package/dist/combinedSense.js +261 -0
  113. package/dist/combinedSense.js.map +1 -0
  114. package/dist/config.d.ts +351 -0
  115. package/dist/config.d.ts.map +1 -1
  116. package/dist/config.js +99 -2
  117. package/dist/config.js.map +1 -1
  118. package/dist/connectorCadence.d.ts +135 -0
  119. package/dist/connectorCadence.d.ts.map +1 -0
  120. package/dist/connectorCadence.js +151 -0
  121. package/dist/connectorCadence.js.map +1 -0
  122. package/dist/dataDir.d.ts +33 -0
  123. package/dist/dataDir.d.ts.map +1 -0
  124. package/dist/dataDir.js +76 -0
  125. package/dist/dataDir.js.map +1 -0
  126. package/dist/deployedCadence.d.ts +167 -0
  127. package/dist/deployedCadence.d.ts.map +1 -0
  128. package/dist/deployedCadence.js +209 -0
  129. package/dist/deployedCadence.js.map +1 -0
  130. package/dist/deployedCadenceSource.d.ts +48 -0
  131. package/dist/deployedCadenceSource.d.ts.map +1 -0
  132. package/dist/deployedCadenceSource.js +74 -0
  133. package/dist/deployedCadenceSource.js.map +1 -0
  134. package/dist/diagnose.d.ts +1 -1
  135. package/dist/diagnose.d.ts.map +1 -1
  136. package/dist/diagnose.js +15 -13
  137. package/dist/diagnose.js.map +1 -1
  138. package/dist/discovery.d.ts +131 -0
  139. package/dist/discovery.d.ts.map +1 -0
  140. package/dist/discovery.js +499 -0
  141. package/dist/discovery.js.map +1 -0
  142. package/dist/gemmaModelOta.d.ts +118 -0
  143. package/dist/gemmaModelOta.d.ts.map +1 -0
  144. package/dist/gemmaModelOta.js +291 -0
  145. package/dist/gemmaModelOta.js.map +1 -0
  146. package/dist/index.d.ts +16 -1
  147. package/dist/index.d.ts.map +1 -1
  148. package/dist/index.js +40 -1
  149. package/dist/index.js.map +1 -1
  150. package/dist/init.d.ts.map +1 -1
  151. package/dist/init.js +25 -87
  152. package/dist/init.js.map +1 -1
  153. package/dist/keepAwake.d.ts +33 -0
  154. package/dist/keepAwake.d.ts.map +1 -0
  155. package/dist/keepAwake.js +54 -0
  156. package/dist/keepAwake.js.map +1 -0
  157. package/dist/legacyRecorderProfile.d.ts +20 -0
  158. package/dist/legacyRecorderProfile.d.ts.map +1 -0
  159. package/dist/legacyRecorderProfile.js +27 -0
  160. package/dist/legacyRecorderProfile.js.map +1 -0
  161. package/dist/localInferenceSchema.d.ts +132 -0
  162. package/dist/localInferenceSchema.d.ts.map +1 -0
  163. package/dist/localInferenceSchema.js +274 -0
  164. package/dist/localInferenceSchema.js.map +1 -0
  165. package/dist/localSenseE2eHarness.d.ts +101 -0
  166. package/dist/localSenseE2eHarness.d.ts.map +1 -0
  167. package/dist/localSenseE2eHarness.js +279 -0
  168. package/dist/localSenseE2eHarness.js.map +1 -0
  169. package/dist/localSensing.d.ts +284 -0
  170. package/dist/localSensing.d.ts.map +1 -0
  171. package/dist/localSensing.js +512 -0
  172. package/dist/localSensing.js.map +1 -0
  173. package/dist/mcp-server.d.ts.map +1 -1
  174. package/dist/mcp-server.js +3 -1
  175. package/dist/mcp-server.js.map +1 -1
  176. package/dist/modelIntegrity.d.ts +80 -0
  177. package/dist/modelIntegrity.d.ts.map +1 -0
  178. package/dist/modelIntegrity.js +194 -0
  179. package/dist/modelIntegrity.js.map +1 -0
  180. package/dist/pairVerify.d.ts +100 -0
  181. package/dist/pairVerify.d.ts.map +1 -0
  182. package/dist/pairVerify.js +296 -0
  183. package/dist/pairVerify.js.map +1 -0
  184. package/dist/qrScanner.d.ts +33 -0
  185. package/dist/qrScanner.d.ts.map +1 -0
  186. package/dist/qrScanner.js +103 -0
  187. package/dist/qrScanner.js.map +1 -0
  188. package/dist/runtimePaths.d.ts +10 -0
  189. package/dist/runtimePaths.d.ts.map +1 -0
  190. package/dist/runtimePaths.js +79 -0
  191. package/dist/runtimePaths.js.map +1 -0
  192. package/dist/sensingRunMode.d.ts +86 -0
  193. package/dist/sensingRunMode.d.ts.map +1 -0
  194. package/dist/sensingRunMode.js +346 -0
  195. package/dist/sensingRunMode.js.map +1 -0
  196. package/dist/setupMode.d.ts +98 -0
  197. package/dist/setupMode.d.ts.map +1 -0
  198. package/dist/setupMode.js +828 -0
  199. package/dist/setupMode.js.map +1 -0
  200. package/dist/setupProgress.d.ts +31 -0
  201. package/dist/setupProgress.d.ts.map +1 -0
  202. package/dist/setupProgress.js +173 -0
  203. package/dist/setupProgress.js.map +1 -0
  204. package/package.json +13 -4
@@ -0,0 +1,606 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.defaultHttpGetter = exports.AutoSenseSupervisor = void 0;
37
+ exports.probeLiteRtLmHealth = probeLiteRtLmHealth;
38
+ exports.runAutoSense = runAutoSense;
39
+ const http = __importStar(require("http"));
40
+ const https = __importStar(require("https"));
41
+ const url_1 = require("url");
42
+ const config_1 = require("./config");
43
+ const sensingRunMode_1 = require("./sensingRunMode");
44
+ const gemmaModelOta_1 = require("./gemmaModelOta");
45
+ /**
46
+ * `auto-sense` — the ONE dispatching entrypoint for the BYO-CCTV connector that
47
+ * prefers ON-DEVICE local sensing (LiteRT-LM serving Gemma). Cloud inference is
48
+ * available only when the operator explicitly enables it.
49
+ *
50
+ * A fresh install may start before its model download finishes, so this probes
51
+ * `litert-lm serve` health with a SHORT timeout and:
52
+ * - healthy → runs the EXISTING local-sense path (no Vertex cost)
53
+ * - unhealthy/unreachable → waits and keeps probing without uploading frames
54
+ * - unhealthy + allowCloudFallback=true → runs the cloud-sense path
55
+ *
56
+ * It introduces NO new providers and NO duplicated sensing logic — the local
57
+ * and cloud run modes are reused verbatim. This module only owns the SELECTION.
58
+ */
59
+ const DEFAULT_LITERT_LM_BASE_URL = 'http://localhost:9379';
60
+ /** Default model the local-sense path runs (must match config.localSensing.model). */
61
+ const DEFAULT_LITERT_LM_MODEL = 'gemma-4-E2B-it.litertlm';
62
+ /**
63
+ * Probe timeout. SHORT on purpose: on a box with no litert-lm the connect
64
+ * either refuses fast (ECONNREFUSED) or hangs, and readiness checks should not
65
+ * stall the connector behind a long wait.
66
+ */
67
+ const DEFAULT_PROBE_TIMEOUT_MS = 2000;
68
+ /**
69
+ * Startup re-probe budget. A fresh install races litert-lm warmup/model-download
70
+ * (e.g. Windows `setup-litertlm.ps1` runs detached while the scheduled task can
71
+ * start right after pairing). A single probe at boot would pick cloud and never
72
+ * re-probe, stranding the box on cloud until a manual restart. So at startup we
73
+ * re-probe a few times before entering the steady waiting state. Default 4
74
+ * attempts.
75
+ */
76
+ const DEFAULT_STARTUP_PROBE_ATTEMPTS = 4;
77
+ /** Delay between startup re-probes (ms). Default 5s → ~15s warmup window. */
78
+ const DEFAULT_STARTUP_PROBE_BACKOFF_MS = 5000;
79
+ /**
80
+ * Steady-state background re-probe interval (ms). AFTER auto-sense picks a mode it
81
+ * keeps probing on this cadence so it can start local inference once a fresh
82
+ * install's litert-lm finishes warming up. Explicit cloud-fallback installs also
83
+ * use it to upgrade cloud→local and recover local→cloud. Default 60s.
84
+ */
85
+ const DEFAULT_HEALTH_RECHECK_INTERVAL_MS = 60000;
86
+ /** Floor for the re-probe interval (ms) so a mis-set tiny value can't hammer the serve. */
87
+ const MIN_HEALTH_RECHECK_INTERVAL_MS = 15000;
88
+ /**
89
+ * Anti-thrash: consecutive UNHEALTHY background re-probes required before a
90
+ * LOCAL→CLOUD fallback (a single flapping bad probe must not toggle the active
91
+ * manager). The reverse cloud→local upgrade is immediate. Default 2.
92
+ */
93
+ const DEFAULT_LOCAL_UNHEALTHY_CHECKS_BEFORE_FALLBACK = 2;
94
+ /**
95
+ * Probe `litert-lm serve` for reachability + readiness via `GET {base}/v1/models`
96
+ * (the OpenAI-compatible model list — cheap, present on a healthy serve, and a
97
+ * de-facto health endpoint). A 2xx with a parseable model list THAT INCLUDES THE
98
+ * MODEL the local-sense path will actually use is "healthy"; anything else
99
+ * (connection refused, timeout, non-2xx, empty/garbage body, OR a serve hosting
100
+ * a DIFFERENT model than configured) is "unhealthy" so the caller degrades to
101
+ * cloud.
102
+ *
103
+ * Why match the model (not just "non-empty list"): the local path posts inference
104
+ * to `config.localSensing.model` (default gemma-4-E2B-it.litertlm). A serve that
105
+ * is up but hosting a DIFFERENT model id would make auto-sense pick local and
106
+ * then fail EVERY frame — exactly the hard-fail this entrypoint exists to avoid.
107
+ * So we require the expected model to be present. (`expectedModel` omitted → fall
108
+ * back to "any non-empty list", e.g. for a pure reachability check.)
109
+ *
110
+ * Built-in http/https only (no extra dependency → survives bundling into the
111
+ * self-contained connector; trivially mockable in tests). Never throws.
112
+ */
113
+ async function probeLiteRtLmHealth(baseUrl = DEFAULT_LITERT_LM_BASE_URL, opts = {}) {
114
+ const base = (baseUrl || DEFAULT_LITERT_LM_BASE_URL).replace(/\/+$/, '');
115
+ const url = `${base}/v1/models`;
116
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
117
+ const getter = opts.httpGetter ?? exports.defaultHttpGetter;
118
+ const expectedModel = opts.expectedModel?.trim() || undefined;
119
+ const startedAt = Date.now();
120
+ let result;
121
+ try {
122
+ result = await getter(url, { timeoutMs });
123
+ }
124
+ catch (err) {
125
+ return {
126
+ ok: false,
127
+ reason: `litert-lm unreachable at ${url} (${err.message})`,
128
+ };
129
+ }
130
+ const latencyMs = Date.now() - startedAt;
131
+ if (result.statusCode < 200 || result.statusCode >= 300) {
132
+ return {
133
+ ok: false,
134
+ reason: `litert-lm at ${url} returned HTTP ${result.statusCode}`,
135
+ latencyMs,
136
+ statusCode: result.statusCode,
137
+ };
138
+ }
139
+ // A healthy serve answers /v1/models with `{ data: [ { id, ... } ] }`. Collect
140
+ // the model ids so we can require BOTH a non-empty list AND (when asked) the
141
+ // specific model the local path will use.
142
+ let modelIds = null;
143
+ try {
144
+ const parsed = JSON.parse(result.body);
145
+ if (Array.isArray(parsed?.data)) {
146
+ modelIds = parsed.data
147
+ .map((m) => (m && typeof m.id === 'string' ? m.id : null))
148
+ .filter((id) => id !== null);
149
+ }
150
+ }
151
+ catch {
152
+ modelIds = null;
153
+ }
154
+ if (modelIds === null) {
155
+ return {
156
+ ok: false,
157
+ reason: `litert-lm at ${url} returned an unparseable model list`,
158
+ latencyMs,
159
+ statusCode: result.statusCode,
160
+ };
161
+ }
162
+ if (modelIds.length === 0) {
163
+ return {
164
+ ok: false,
165
+ reason: `litert-lm at ${url} is up but has no model imported`,
166
+ latencyMs,
167
+ statusCode: result.statusCode,
168
+ };
169
+ }
170
+ // The serve is up with model(s), but if it isn't hosting the one we'll infer
171
+ // against, local would fail every frame — so treat that as unhealthy → cloud.
172
+ if (expectedModel && !modelIds.includes(expectedModel)) {
173
+ return {
174
+ ok: false,
175
+ reason: `litert-lm at ${url} is up but does not host model "${expectedModel}" ` +
176
+ `(has: ${modelIds.join(', ')})`,
177
+ latencyMs,
178
+ statusCode: result.statusCode,
179
+ };
180
+ }
181
+ return {
182
+ ok: true,
183
+ reason: `litert-lm healthy at ${url} (` +
184
+ (expectedModel ? `model "${expectedModel}" present, ` : `${modelIds.length} model(s), `) +
185
+ `${latencyMs}ms)`,
186
+ latencyMs,
187
+ statusCode: result.statusCode,
188
+ };
189
+ }
190
+ /**
191
+ * The `auto-sense` SUPERVISOR. Instead of probing once and then blocking forever
192
+ * on a single manager (the old behavior — mode FIXED for the whole process run,
193
+ * "restart to re-probe"), it OWNS the sensing lifecycle so the connector always
194
+ * prefers on-device Gemma and switches automatically with NO restart:
195
+ *
196
+ * - startInitial(): bounded startup re-probe → start the chosen path's REAL
197
+ * manager directly when litert-lm is healthy; otherwise wait locally unless
198
+ * cloud fallback was explicitly enabled.
199
+ * - beginRechecks(): a steady-state background re-probe loop on recheckIntervalMs.
200
+ * - recheck(): one tick — AUTO-UPGRADE cloud→local the instant local is ready
201
+ * (fixes the fresh-install race with zero restart). Explicit cloud-fallback
202
+ * installs may also recover local→cloud after K unhealthy probes.
203
+ * - shutdown(): stop the active manager + clear the timer (SIGINT/SIGTERM).
204
+ *
205
+ * At most ONE switch per tick; a re-entrancy guard + the K-debounce mean a
206
+ * flapping health signal can never rapidly toggle managers.
207
+ */
208
+ class AutoSenseSupervisor {
209
+ constructor(deps) {
210
+ this.deps = deps;
211
+ this.mode = null;
212
+ this.active = null;
213
+ // Build each mode's manager once and reuse the instance across switches (a
214
+ // stop()→start() cycle re-runs the SAME real manager). `undefined` = not built
215
+ // yet; `null` = built but no feeds (fatal — cached so we don't rebuild).
216
+ this.localManager = undefined;
217
+ this.cloudManager = undefined;
218
+ this.consecutiveUnhealthy = 0;
219
+ /**
220
+ * Completed local analyses as of the previous re-probe. `null` = no baseline
221
+ * yet (not on local, or the manager cannot report it), which reads as "no
222
+ * positive evidence" and leaves the pre-existing behaviour in place.
223
+ */
224
+ this.analysesAtLastRecheck = null;
225
+ this.timer = null;
226
+ this.switching = false;
227
+ this.stopped = false;
228
+ }
229
+ /** The active mode (null until startInitial). For tests/observability. */
230
+ get currentMode() {
231
+ return this.mode;
232
+ }
233
+ getManager(mode) {
234
+ if (mode === 'local') {
235
+ if (this.localManager === undefined)
236
+ this.localManager = this.deps.buildLocalManager();
237
+ return this.localManager;
238
+ }
239
+ if (this.cloudManager === undefined)
240
+ this.cloudManager = this.deps.buildCloudManager();
241
+ return this.cloudManager;
242
+ }
243
+ /**
244
+ * Initial probe (bounded startup re-probe loop for the fresh-install warmup
245
+ * race) → start the chosen path's manager directly. Returns false (after
246
+ * onNoFeeds) when the chosen mode has no feeds configured.
247
+ */
248
+ async startInitial() {
249
+ this.deps.log(`[auto-sense] probing on-device LiteRT-LM at ${this.deps.litertLmBaseUrl} for model ` +
250
+ `"${this.deps.expectedModel}" (timeout ${this.deps.probeTimeoutMs}ms, up to ` +
251
+ `${this.deps.startupAttempts} attempt(s))…`);
252
+ let health = { ok: false, reason: 'no probe attempt made' };
253
+ for (let attempt = 1; attempt <= this.deps.startupAttempts; attempt += 1) {
254
+ health = await this.deps.probe();
255
+ if (health.ok)
256
+ break;
257
+ if (attempt < this.deps.startupAttempts) {
258
+ this.deps.log(`[auto-sense] LiteRT-LM not ready (attempt ${attempt}/${this.deps.startupAttempts}): ` +
259
+ `${health.reason} — retrying in ${this.deps.startupBackoffMs}ms`);
260
+ if (this.deps.startupBackoffMs > 0)
261
+ await this.deps.sleep(this.deps.startupBackoffMs);
262
+ }
263
+ }
264
+ if (health.ok) {
265
+ this.deps.log(`[auto-sense] LOCAL on-device sensing selected — ${health.reason}`);
266
+ return this.activate('local');
267
+ }
268
+ if (this.deps.allowCloudFallback) {
269
+ this.deps.log(`[auto-sense] CLOUD sensing selected by explicit fallback policy (local VLM not usable after ` +
270
+ `${this.deps.startupAttempts} attempt(s)) — ${health.reason}. Will AUTO-UPGRADE to LOCAL ` +
271
+ `with no restart once LiteRT-LM is ready (re-probing every ${this.deps.recheckIntervalMs}ms).`);
272
+ return this.activate('cloud');
273
+ }
274
+ // Validate feeds before entering the wait loop so a bad/empty config still
275
+ // fails immediately instead of looking like a model download in progress.
276
+ if (!this.getManager('local')) {
277
+ this.deps.onNoFeeds();
278
+ return false;
279
+ }
280
+ this.mode = 'waiting';
281
+ this.deps.log(`[auto-sense] LOCAL AI is not ready yet — ${health.reason}. Cloud inference is disabled by ` +
282
+ `default; waiting for LiteRT-LM and re-probing every ${this.deps.recheckIntervalMs}ms.`);
283
+ return true;
284
+ }
285
+ /** Build + start a mode's manager and make it active. False ⇒ no feeds. */
286
+ async activate(mode) {
287
+ const manager = this.getManager(mode);
288
+ if (!manager) {
289
+ this.deps.onNoFeeds();
290
+ return false;
291
+ }
292
+ await manager.start();
293
+ this.active = manager;
294
+ this.mode = mode;
295
+ this.consecutiveUnhealthy = 0;
296
+ // `start()` resets the manager's per-run analysis counter, so the baseline
297
+ // has to be re-taken here or the first re-probe would compare against a
298
+ // count from a previous run.
299
+ this.analysesAtLastRecheck = mode === 'local' ? this.localInferencesCompleted() : null;
300
+ if (mode === 'local')
301
+ this.deps.onLocalActivated?.();
302
+ return true;
303
+ }
304
+ /** Start the steady-state background re-probe loop. */
305
+ beginRechecks() {
306
+ this.scheduleNextRecheck();
307
+ }
308
+ scheduleNextRecheck() {
309
+ if (this.stopped)
310
+ return;
311
+ // Re-arming timeout (schedule the NEXT tick only after this one settles) so
312
+ // a slow probe/switch can never overlap the next re-probe.
313
+ this.timer = this.deps.setTimer(() => {
314
+ this.recheck()
315
+ .catch((err) => this.deps.log(`[auto-sense] re-probe tick failed: ${err instanceof Error ? err.message : err}`))
316
+ .finally(() => this.scheduleNextRecheck());
317
+ }, this.deps.recheckIntervalMs);
318
+ }
319
+ /**
320
+ * How many ON-DEVICE inferences have completed this run. `null` when the
321
+ * manager cannot report it (a test fake, a not-yet-built manager) — which
322
+ * reads as "no positive evidence", i.e. today's behaviour.
323
+ */
324
+ localInferencesCompleted() {
325
+ const manager = this.localManager;
326
+ if (!manager || typeof manager.getSensingHealth !== 'function')
327
+ return null;
328
+ try {
329
+ const n = manager.getSensingHealth().localInferences;
330
+ return Number.isFinite(n) ? n : null;
331
+ }
332
+ catch {
333
+ return null;
334
+ }
335
+ }
336
+ /**
337
+ * One background re-probe tick.
338
+ * - While WAITING: a healthy probe starts local sensing immediately.
339
+ * - On CLOUD: any healthy probe → AUTO-UPGRADE to local immediately (running
340
+ * on cloud while local is ready is pure waste; the K-debounce on the return
341
+ * path bounds any toggling, so this is safe on the first healthy probe).
342
+ * - On LOCAL: a healthy probe resets the debounce; an unhealthy probe
343
+ * increments it, and only after K CONSECUTIVE unhealthy probes do we
344
+ * AUTO-RECOVER to cloud only when explicit fallback is enabled.
345
+ * At most one switch per tick; re-entrancy guarded.
346
+ *
347
+ * ── Why an unanswered probe is not, by itself, a verdict ───────────────────
348
+ *
349
+ * `litert-lm serve` builds on `http.server.HTTPServer` — the SERIAL one, not
350
+ * `ThreadingHTTPServer`. One request is handled at a time, so for the whole
351
+ * duration of a generation the accept loop is blocked and `GET /v1/models`
352
+ * cannot be answered by anybody. The readiness probe therefore competes with
353
+ * the very work whose viability it is meant to certify: measured against the
354
+ * real serve, 4 of 5 probes issued during ONE 11.8 s inference timed out at
355
+ * the shipped 2 000 ms, while an idle serve answered the same request in
356
+ * 2.6 ms.
357
+ *
358
+ * A 16-camera connector keeps that single slot busy essentially all the time,
359
+ * so an UNANSWERED probe was near-certain and two consecutive ones demoted the
360
+ * whole install: measured 3 mode switches in the first 6 minutes of a
361
+ * 16-camera run, each one stopping and restarting all 16 loops and moving
362
+ * every feed onto the metered cloud path. The connector's own success at
363
+ * local inference was the thing that made local inference look dead.
364
+ *
365
+ * The evidence that settles it is not the ping, it is the WORK: an ON-DEVICE
366
+ * inference that COMPLETED since the previous re-probe proves the runtime is
367
+ * alive, and proves it more directly than any side-channel could. So an
368
+ * unanswered probe is inconclusive only while local inferences are still
369
+ * landing; the moment they stop landing the same probe counts, and K of them
370
+ * demote exactly as before.
371
+ *
372
+ * It has to be `localInferences` and not the total analysis count. With
373
+ * `cloudFallbackOnError` on, a frame the local provider THREW on is answered
374
+ * by the cloud and still lands as an analysis — so a dead runtime would keep
375
+ * advancing the total forever and this rule would mask it permanently, which
376
+ * is strictly worse than the defect it replaces.
377
+ *
378
+ * Deliberately NOT keyed on "we have a request in flight": a serve that
379
+ * ACCEPTS and never answers holds our permit for the provider's whole timeout,
380
+ * so in-flight work is compatible with a runtime that is doing nothing. Only
381
+ * completion is proof. An ANSWERED probe stays conclusive either way — a
382
+ * non-2xx or a wrong model list is a real verdict, and a serve that answers
383
+ * has an opinion.
384
+ */
385
+ async recheck() {
386
+ if (this.stopped || this.switching)
387
+ return;
388
+ const analysesBefore = this.analysesAtLastRecheck;
389
+ const health = await this.deps.probe();
390
+ if (this.stopped)
391
+ return;
392
+ const analysesNow = this.localInferencesCompleted();
393
+ // Positive proof of life: the ON-DEVICE runtime finished work in this window.
394
+ const provedAliveByWork = analysesNow !== null && analysesBefore !== null && analysesNow > analysesBefore;
395
+ this.analysesAtLastRecheck = analysesNow;
396
+ if (this.mode === 'waiting') {
397
+ if (health.ok) {
398
+ this.deps.log('[auto-sense] LOCAL AI is ready — starting on-device sensing');
399
+ await this.switchTo('local');
400
+ }
401
+ return;
402
+ }
403
+ if (this.mode === 'cloud') {
404
+ if (health.ok) {
405
+ this.deps.log('[auto-sense] upgrading CLOUD->LOCAL (LiteRT-LM now ready)');
406
+ await this.switchTo('local');
407
+ }
408
+ return;
409
+ }
410
+ if (this.mode === 'local') {
411
+ if (health.ok) {
412
+ this.consecutiveUnhealthy = 0;
413
+ return;
414
+ }
415
+ // Unanswered (no statusCode) while local analyses are still COMPLETING:
416
+ // inconclusive. Neither counted nor cleared — ask again next interval.
417
+ if (health.statusCode === undefined && provedAliveByWork) {
418
+ this.deps.log(`[auto-sense] health probe inconclusive — the single litert-lm slot cannot answer ` +
419
+ `/v1/models while it generates (${health.reason}), and this connector completed ` +
420
+ `${(analysesNow ?? 0) - (analysesBefore ?? 0)} on-device inference(s) since the last ` +
421
+ 'check. Not counting it against the fallback debounce.');
422
+ return;
423
+ }
424
+ this.consecutiveUnhealthy += 1;
425
+ if (this.consecutiveUnhealthy >= this.deps.unhealthyChecksBeforeFallback) {
426
+ if (this.deps.allowCloudFallback) {
427
+ // Name the reason. The no-fallback branch below always has; this one
428
+ // did not, so the operator whose bill just moved onto the metered
429
+ // cloud path saw a demotion with no cause attached to it.
430
+ this.deps.log(`[auto-sense] falling back LOCAL->CLOUD (explicit policy; LiteRT-LM unhealthy after ` +
431
+ `${this.consecutiveUnhealthy} consecutive checks) — ${health.reason}`);
432
+ await this.switchTo('cloud');
433
+ }
434
+ else {
435
+ this.deps.log(`[auto-sense] LOCAL AI health check failed — ${health.reason}. ` +
436
+ 'Cloud inference remains disabled; local sensing will recover in place.');
437
+ this.consecutiveUnhealthy = 0;
438
+ }
439
+ }
440
+ }
441
+ }
442
+ /** Stop the active manager, start the target — old.stop() BEFORE new.start(). */
443
+ async switchTo(mode) {
444
+ if (this.mode === mode || this.switching)
445
+ return;
446
+ const next = this.getManager(mode);
447
+ if (!next) {
448
+ // Can't happen mid-run (both modes resolve the SAME static feeds), but
449
+ // never tear down the working manager for one we can't start.
450
+ this.deps.log(`[auto-sense] cannot switch to ${mode} sensing (no camera feeds) — staying on ${this.mode}`);
451
+ return;
452
+ }
453
+ this.switching = true;
454
+ try {
455
+ if (this.active)
456
+ await this.active.stop();
457
+ await next.start();
458
+ this.active = next;
459
+ this.mode = mode;
460
+ this.consecutiveUnhealthy = 0;
461
+ // Same reason as in activate(): start() zeroes the per-run analysis count.
462
+ this.analysesAtLastRecheck = mode === 'local' ? this.localInferencesCompleted() : null;
463
+ if (mode === 'local')
464
+ this.deps.onLocalActivated?.();
465
+ }
466
+ finally {
467
+ this.switching = false;
468
+ }
469
+ }
470
+ /** SIGINT/SIGTERM: stop the active manager + clear the re-probe timer. Idempotent. */
471
+ async shutdown() {
472
+ if (this.stopped)
473
+ return;
474
+ this.stopped = true;
475
+ if (this.timer != null) {
476
+ this.deps.clearTimer(this.timer);
477
+ this.timer = null;
478
+ }
479
+ if (this.active) {
480
+ try {
481
+ await this.active.stop();
482
+ }
483
+ catch {
484
+ // best-effort
485
+ }
486
+ }
487
+ }
488
+ }
489
+ exports.AutoSenseSupervisor = AutoSenseSupervisor;
490
+ function defaultRegisterShutdown(handler) {
491
+ process.on('SIGINT', handler);
492
+ process.on('SIGTERM', handler);
493
+ }
494
+ /** Never resolves — keeps the connector process alive until SIGINT/SIGTERM. */
495
+ function blockForever() {
496
+ return new Promise(() => { });
497
+ }
498
+ /**
499
+ * `auto-sense` entrypoint: resolve probe + manager inputs from config, then run
500
+ * the AutoSenseSupervisor (probe → start the chosen REAL manager → keep
501
+ * re-probing → auto-upgrade/auto-recover with NO restart). Blocks until
502
+ * SIGINT/SIGTERM (the supervisor's re-probe timer keeps the event loop alive).
503
+ *
504
+ * The probe target is the operator's configured `localSensing.litertLmBaseUrl`
505
+ * (default http://localhost:9379) so a non-standard serve host is honored, and
506
+ * the probe requires the configured `localSensing.model` to be present so we
507
+ * never pick local against a serve hosting the wrong model.
508
+ *
509
+ * Config is REQUIRED to build the sensing managers, so it's loaded up front and a
510
+ * genuine config error propagates to main() (prints + exits 1) — the same net
511
+ * result as before, where the chosen run mode re-loaded the config and reported it.
512
+ *
513
+ * The explicit `local-sense` / `cloud-sense` entrypoints stay non-switching; only
514
+ * `auto-sense` is supervised.
515
+ */
516
+ async function runAutoSense(args, deps = {}) {
517
+ const log = deps.log ?? ((m) => console.log(m));
518
+ const load = deps.loadConfig ?? config_1.loadConfig;
519
+ const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
520
+ const configIdx = args.indexOf('--config');
521
+ const configPath = configIdx >= 0 && args[configIdx + 1] ? args[configIdx + 1] : 'trillboards.config.json';
522
+ const config = load(configPath);
523
+ const litertLmBaseUrl = config.localSensing?.litertLmBaseUrl || DEFAULT_LITERT_LM_BASE_URL;
524
+ const probeTimeoutMs = config.localSensing?.healthProbeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
525
+ const expectedModel = config.localSensing?.model || DEFAULT_LITERT_LM_MODEL;
526
+ const startupAttempts = Math.max(1, config.localSensing?.healthProbeStartupAttempts ?? DEFAULT_STARTUP_PROBE_ATTEMPTS);
527
+ const startupBackoffMs = config.localSensing?.healthProbeStartupBackoffMs ?? DEFAULT_STARTUP_PROBE_BACKOFF_MS;
528
+ const recheckIntervalMs = Math.max(MIN_HEALTH_RECHECK_INTERVAL_MS, config.localSensing?.healthRecheckIntervalMs ?? DEFAULT_HEALTH_RECHECK_INTERVAL_MS);
529
+ const unhealthyChecksBeforeFallback = Math.max(1, config.localSensing?.localUnhealthyChecksBeforeFallback ??
530
+ DEFAULT_LOCAL_UNHEALTHY_CHECKS_BEFORE_FALLBACK);
531
+ const allowCloudFallback = config.localSensing?.allowCloudFallback === true;
532
+ const probe = deps.probe
533
+ ? () => deps.probe(litertLmBaseUrl, probeTimeoutMs, expectedModel)
534
+ : () => probeLiteRtLmHealth(litertLmBaseUrl, { timeoutMs: probeTimeoutMs, expectedModel });
535
+ let gemmaOta = null;
536
+ let gemmaOtaStarted = false;
537
+ const startModelOtaOnce = () => {
538
+ if (gemmaOtaStarted)
539
+ return;
540
+ gemmaOtaStarted = true;
541
+ gemmaOta = (deps.startModelOta ?? gemmaModelOta_1.startGemmaModelOta)(config);
542
+ };
543
+ const supervisor = new AutoSenseSupervisor({
544
+ probe,
545
+ buildLocalManager: deps.buildLocalManager ?? (() => (0, sensingRunMode_1.buildLocalSensingManager)(config, undefined, { configPath })),
546
+ buildCloudManager: deps.buildCloudManager ?? (() => (0, sensingRunMode_1.buildCloudSensingManager)(config, undefined, { configPath })),
547
+ log,
548
+ sleep,
549
+ setTimer: deps.setTimer ?? ((cb, ms) => setTimeout(cb, ms)),
550
+ clearTimer: deps.clearTimer ?? ((h) => clearTimeout(h)),
551
+ onNoFeeds: deps.onNoFeeds ?? (() => process.exit(1)),
552
+ onLocalActivated: startModelOtaOnce,
553
+ startupAttempts,
554
+ startupBackoffMs,
555
+ recheckIntervalMs,
556
+ unhealthyChecksBeforeFallback,
557
+ allowCloudFallback,
558
+ litertLmBaseUrl,
559
+ expectedModel,
560
+ probeTimeoutMs,
561
+ });
562
+ // Clean shutdown: stop the OTA watcher, the active manager, + the re-probe timer.
563
+ const register = deps.registerShutdown ?? defaultRegisterShutdown;
564
+ register(async () => {
565
+ gemmaOta?.stop();
566
+ await supervisor.shutdown();
567
+ process.exit(0);
568
+ });
569
+ const started = await supervisor.startInitial();
570
+ if (!started)
571
+ return; // onNoFeeds already fired (default: process.exit(1))
572
+ supervisor.beginRechecks();
573
+ // Keep the process running until SIGINT/SIGTERM (tests inject a resolved waiter).
574
+ await (deps.waitForShutdown ?? blockForever)();
575
+ }
576
+ /**
577
+ * Default transport using Node's built-in http/https. No third-party deps so it
578
+ * survives bundling into the self-contained connector. Mirrors the framing
579
+ * tolerance of LiteRtVlmProvider's poster: litert-lm serve emits non-strict HTTP
580
+ * framing (bare LF on the status line) that Node's strict parser rejects, and
581
+ * the connector talks to a LOCAL, trusted serve, so we tolerate it here too —
582
+ * otherwise a healthy serve would look "unreachable" and we'd wrongly pick cloud.
583
+ */
584
+ const defaultHttpGetter = (url, options) => {
585
+ return new Promise((resolve, reject) => {
586
+ let parsed;
587
+ try {
588
+ parsed = new url_1.URL(url);
589
+ }
590
+ catch (err) {
591
+ reject(new Error(`Invalid LiteRT-LM URL: ${err.message}`));
592
+ return;
593
+ }
594
+ const mod = parsed.protocol === 'https:' ? https : http;
595
+ const req = mod.request(url, { method: 'GET', timeout: options.timeoutMs, insecureHTTPParser: true }, (res) => {
596
+ const chunks = [];
597
+ res.on('data', (chunk) => chunks.push(chunk));
598
+ res.on('end', () => resolve({ statusCode: res.statusCode || 0, body: Buffer.concat(chunks).toString('utf-8') }));
599
+ });
600
+ req.on('error', (err) => reject(err));
601
+ req.on('timeout', () => req.destroy(new Error(`probe timed out after ${options.timeoutMs}ms`)));
602
+ req.end();
603
+ });
604
+ };
605
+ exports.defaultHttpGetter = defaultHttpGetter;
606
+ //# sourceMappingURL=autoSense.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoSense.js","sourceRoot":"","sources":["../src/autoSense.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqGA,kDAoFC;AAkbD,oCAgFC;AA3rBD,2CAA6B;AAC7B,6CAA+B;AAC/B,6BAA0B;AAC1B,qCAA4D;AAC5D,qDAI0B;AAC1B,mDAA+E;AAE/E;;;;;;;;;;;;;GAaG;AAEH,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAC3D,sFAAsF;AACtF,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAC1D;;;;GAIG;AACH,MAAM,wBAAwB,GAAG,IAAK,CAAC;AACvC;;;;;;;GAOG;AACH,MAAM,8BAA8B,GAAG,CAAC,CAAC;AACzC,6EAA6E;AAC7E,MAAM,gCAAgC,GAAG,IAAK,CAAC;AAC/C;;;;;GAKG;AACH,MAAM,kCAAkC,GAAG,KAAM,CAAC;AAClD,2FAA2F;AAC3F,MAAM,8BAA8B,GAAG,KAAM,CAAC;AAC9C;;;;GAIG;AACH,MAAM,8CAA8C,GAAG,CAAC,CAAC;AAsBzD;;;;;;;;;;;;;;;;;;GAkBG;AACI,KAAK,UAAU,mBAAmB,CACvC,UAAkB,0BAA0B,EAC5C,OAAgF,EAAE;IAElF,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,0BAA0B,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzE,MAAM,GAAG,GAAG,GAAG,IAAI,YAAY,CAAC;IAChC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,wBAAwB,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,IAAI,yBAAiB,CAAC;IACpD,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAE9D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,MAA4C,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,4BAA4B,GAAG,KAAM,GAAa,CAAC,OAAO,GAAG;SACtE,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAEzC,IAAI,MAAM,CAAC,UAAU,GAAG,GAAG,IAAI,MAAM,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;QACxD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,gBAAgB,GAAG,kBAAkB,MAAM,CAAC,UAAU,EAAE;YAChE,SAAS;YACT,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,6EAA6E;IAC7E,0CAA0C;IAC1C,IAAI,QAAQ,GAAoB,IAAI,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAuC,CAAC;QAC7E,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YAChC,QAAQ,GAAG,MAAM,CAAC,IAAI;iBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBACzD,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,gBAAgB,GAAG,qCAAqC;YAChE,SAAS;YACT,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,gBAAgB,GAAG,kCAAkC;YAC7D,SAAS;YACT,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IACD,6EAA6E;IAC7E,8EAA8E;IAC9E,IAAI,aAAa,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACvD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EACJ,gBAAgB,GAAG,mCAAmC,aAAa,IAAI;gBACvE,SAAS,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YACjC,SAAS;YACT,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EACJ,wBAAwB,GAAG,IAAI;YAC/B,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,aAAa,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,aAAa,CAAC;YACxF,GAAG,SAAS,KAAK;QACnB,SAAS;QACT,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC;AACJ,CAAC;AAiDD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,mBAAmB;IAmB9B,YAA6B,IAA6B;QAA7B,SAAI,GAAJ,IAAI,CAAyB;QAlBlD,SAAI,GAA0B,IAAI,CAAC;QACnC,WAAM,GAA0B,IAAI,CAAC;QAC7C,2EAA2E;QAC3E,+EAA+E;QAC/E,yEAAyE;QACjE,iBAAY,GAAsC,SAAS,CAAC;QAC5D,iBAAY,GAAsC,SAAS,CAAC;QAC5D,yBAAoB,GAAG,CAAC,CAAC;QACjC;;;;WAIG;QACK,0BAAqB,GAAkB,IAAI,CAAC;QAC5C,UAAK,GAAgC,IAAI,CAAC;QAC1C,cAAS,GAAG,KAAK,CAAC;QAClB,YAAO,GAAG,KAAK,CAAC;IAEqC,CAAC;IAE9D,0EAA0E;IAC1E,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEO,UAAU,CAAC,IAAiB;QAClC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;gBAAE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvF,OAAO,IAAI,CAAC,YAAY,CAAC;QAC3B,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;YAAE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvF,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,+CAA+C,IAAI,CAAC,IAAI,CAAC,eAAe,aAAa;YACnF,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,cAAc,IAAI,CAAC,IAAI,CAAC,cAAc,YAAY;YAC7E,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,eAAe,CAC9C,CAAC;QAEF,IAAI,MAAM,GAAuB,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;QAChF,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YACzE,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACjC,IAAI,MAAM,CAAC,EAAE;gBAAE,MAAM;YACrB,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;gBACxC,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,6CAA6C,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,eAAe,KAAK;oBACpF,GAAG,MAAM,CAAC,MAAM,kBAAkB,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,CACnE,CAAC;gBACF,IAAI,IAAI,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC;oBAAE,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACxF,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,mDAAmD,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAClF,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,8FAA8F;gBAC5F,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,kBAAkB,MAAM,CAAC,MAAM,+BAA+B;gBAC1F,6DAA6D,IAAI,CAAC,IAAI,CAAC,iBAAiB,MAAM,CACjG,CAAC;YACF,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QAED,2EAA2E;QAC3E,0EAA0E;QAC1E,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,4CAA4C,MAAM,CAAC,MAAM,mCAAmC;YAC1F,uDAAuD,IAAI,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAC1F,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2EAA2E;IACnE,KAAK,CAAC,QAAQ,CAAC,IAAiB;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;QAC9B,2EAA2E;QAC3E,wEAAwE;QACxE,6BAA6B;QAC7B,IAAI,CAAC,qBAAqB,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,IAAI,IAAI,KAAK,OAAO;YAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uDAAuD;IACvD,aAAa;QACX,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAC7B,CAAC;IAEO,mBAAmB;QACzB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,4EAA4E;QAC5E,2DAA2D;QAC3D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,OAAO,EAAE;iBACX,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,sCAAsC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CACjF,CACF;iBACA,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC;QAC/C,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACK,wBAAwB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;QAClC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,gBAAgB,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC;QAC5E,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,eAAe,CAAC;YACrD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3C,MAAM,cAAc,GAAG,IAAI,CAAC,qBAAqB,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,MAAM,WAAW,GAAG,IAAI,CAAC,wBAAwB,EAAE,CAAC;QACpD,8EAA8E;QAC9E,MAAM,iBAAiB,GACrB,WAAW,KAAK,IAAI,IAAI,cAAc,KAAK,IAAI,IAAI,WAAW,GAAG,cAAc,CAAC;QAClF,IAAI,CAAC,qBAAqB,GAAG,WAAW,CAAC;QAEzC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;gBAC7E,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;gBAC3E,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;gBAC9B,OAAO;YACT,CAAC;YACD,wEAAwE;YACxE,uEAAuE;YACvE,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,iBAAiB,EAAE,CAAC;gBACzD,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,mFAAmF;oBACjF,kCAAkC,MAAM,CAAC,MAAM,kCAAkC;oBACjF,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,CAAC,yCAAyC;oBACtF,uDAAuD,CAC1D,CAAC;gBACF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,oBAAoB,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,IAAI,CAAC,6BAA6B,EAAE,CAAC;gBACzE,IAAI,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACjC,qEAAqE;oBACrE,kEAAkE;oBAClE,0DAA0D;oBAC1D,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,qFAAqF;wBACnF,GAAG,IAAI,CAAC,oBAAoB,0BAA0B,MAAM,CAAC,MAAM,EAAE,CACxE,CAAC;oBACF,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAC/B,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,+CAA+C,MAAM,CAAC,MAAM,IAAI;wBAC9D,wEAAwE,CAC3E,CAAC;oBACF,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,iFAAiF;IACzE,KAAK,CAAC,QAAQ,CAAC,IAAiB;QACtC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,uEAAuE;YACvE,8DAA8D;YAC9D,IAAI,CAAC,IAAI,CAAC,GAAG,CACX,iCAAiC,IAAI,2CAA2C,IAAI,CAAC,IAAI,EAAE,CAC5F,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC1C,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;YAC9B,2EAA2E;YAC3E,IAAI,CAAC,qBAAqB,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACvF,IAAI,IAAI,KAAK,OAAO;gBAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QACvD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,sFAAsF;IACtF,KAAK,CAAC,QAAQ;QACZ,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA5SD,kDA4SC;AAuCD,SAAS,uBAAuB,CAAC,OAAmC;IAClE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,+EAA+E;AAC/E,SAAS,YAAY;IACnB,OAAO,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACI,KAAK,UAAU,YAAY,CAAC,IAAc,EAAE,OAAsB,EAAE;IACzE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,IAAI,mBAAU,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAE1F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,UAAU,GACd,SAAS,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC;IAE1F,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAEhC,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,EAAE,eAAe,IAAI,0BAA0B,CAAC;IAC3F,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,EAAE,oBAAoB,IAAI,wBAAwB,CAAC;IAC7F,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,EAAE,KAAK,IAAI,uBAAuB,CAAC;IAC5E,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAC9B,CAAC,EACD,MAAM,CAAC,YAAY,EAAE,0BAA0B,IAAI,8BAA8B,CAClF,CAAC;IACF,MAAM,gBAAgB,GACpB,MAAM,CAAC,YAAY,EAAE,2BAA2B,IAAI,gCAAgC,CAAC;IACvF,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAChC,8BAA8B,EAC9B,MAAM,CAAC,YAAY,EAAE,uBAAuB,IAAI,kCAAkC,CACnF,CAAC;IACF,MAAM,6BAA6B,GAAG,IAAI,CAAC,GAAG,CAC5C,CAAC,EACD,MAAM,CAAC,YAAY,EAAE,kCAAkC;QACrD,8CAA8C,CACjD,CAAC;IACF,MAAM,kBAAkB,GAAG,MAAM,CAAC,YAAY,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAE5E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK;QACtB,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAM,CAAC,eAAe,EAAE,cAAc,EAAE,aAAa,CAAC;QACnE,CAAC,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,CAAC;IAE7F,IAAI,QAAQ,GAA+B,IAAI,CAAC;IAChD,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,MAAM,iBAAiB,GAAG,GAAS,EAAE;QACnC,IAAI,eAAe;YAAE,OAAO;QAC5B,eAAe,GAAG,IAAI,CAAC;QACvB,QAAQ,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,kCAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,mBAAmB,CAAC;QACzC,KAAK;QACL,iBAAiB,EACf,IAAI,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAA,yCAAwB,EAAC,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/F,iBAAiB,EACf,IAAI,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAA,yCAAwB,EAAC,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/F,GAAG;QACH,KAAK;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvD,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,gBAAgB,EAAE,iBAAiB;QACnC,eAAe;QACf,gBAAgB;QAChB,iBAAiB;QACjB,6BAA6B;QAC7B,kBAAkB;QAClB,eAAe;QACf,aAAa;QACb,cAAc;KACf,CAAC,CAAC;IAEH,kFAAkF;IAClF,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,IAAI,uBAAuB,CAAC;IAClE,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,QAAQ,EAAE,IAAI,EAAE,CAAC;QACjB,MAAM,UAAU,CAAC,QAAQ,EAAE,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC;IAChD,IAAI,CAAC,OAAO;QAAE,OAAO,CAAC,qDAAqD;IAE3E,UAAU,CAAC,aAAa,EAAE,CAAC;IAE3B,kFAAkF;IAClF,MAAM,CAAC,IAAI,CAAC,eAAe,IAAI,YAAY,CAAC,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;GAOG;AACI,MAAM,iBAAiB,GAAe,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;IAC5D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,SAAG,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA2B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CACrB,GAAG,EACH,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,kBAAkB,EAAE,IAAI,EAAE,EACvE,CAAC,GAAG,EAAE,EAAE;YACN,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CACjB,OAAO,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAC5F,CAAC;QACJ,CAAC,CACF,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,yBAAyB,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;QAChG,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAzBW,QAAA,iBAAiB,qBAyB5B"}
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,29 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ /**
3
+ * True if a filesystem error is a PERMISSION failure (EACCES/EPERM), or its
4
+ * message says so. This is the signature of the paired-config write failing
5
+ * because ~/Library/Application Support/Trillboards is owned by another account
6
+ * — which happens when the `.pkg` was installed with admin rights and its
7
+ * postinstall ran as root, creating that dir ROOT-OWNED. It is NOT a bad or
8
+ * expired claim code, so it must never be reported as one.
9
+ */
10
+ export declare function isPermissionError(err: unknown): boolean;
11
+ /**
12
+ * The operator-facing remediation when the paired config can't be written
13
+ * because its directory is owned by another account. Names the REAL cause and
14
+ * the exact one-line fix — deliberately NOT "double-check the code" (pairing
15
+ * already SUCCEEDED; only the local save failed). Mirrors the guidance in
16
+ * deploy/macos/pair.command so the GUI and headless paths say the same thing.
17
+ */
18
+ export declare function configWritePermissionMessage(resolvedConfigPath: string): string;
19
+ /**
20
+ * Persist the paired config, translating a PERMISSION failure into the clear
21
+ * remediation above (and exiting non-zero) instead of letting a raw EACCES
22
+ * bubble up as an opaque "Fatal error" that the GUI then mislabels "check the
23
+ * code". Any OTHER write error is re-thrown unchanged (surfaced as "Fatal
24
+ * error: …"). The writer is injectable for tests (mirrors PairClient's poster).
25
+ */
26
+ export declare function writePairedConfig(resolvedConfigPath: string, serialized: string, writeFile?: (p: string, data: string, opts: {
27
+ mode: number;
28
+ }) => void): void;
3
29
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA2WA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAW/E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,MAAM,EAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KAAK,IAC/B,GAChC,IAAI,CAWN"}