@readymadeit/mcp 0.0.0-stage → 0.1.0

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 (916) hide show
  1. package/README.md +114 -2
  2. package/bundle/LICENSE +201 -0
  3. package/bundle/boards/aggregator-demo-board.json +54 -0
  4. package/bundle/boards/alpaca-board.json +316 -0
  5. package/bundle/boards/animate-board.json +159 -0
  6. package/bundle/boards/ascii-art-demo-board.json +33 -0
  7. package/bundle/boards/ascii-cam-board.json +184 -0
  8. package/bundle/boards/asset-demo-board.json +54 -0
  9. package/bundle/boards/audio-encode-demo-board.json +153 -0
  10. package/bundle/boards/audiolize-board.json +152 -0
  11. package/bundle/boards/batcher-demo-board.json +43 -0
  12. package/bundle/boards/buffer-demo-board.json +53 -0
  13. package/bundle/boards/cache-demo-board.json +59 -0
  14. package/bundle/boards/camera-demo-board.json +28 -0
  15. package/bundle/boards/canvas-demo-board.json +55 -0
  16. package/bundle/boards/changes-demo-board.json +60 -0
  17. package/bundle/boards/court-booking-browser-demo-board.json +221 -0
  18. package/bundle/boards/court-booking-demo-board.json +218 -0
  19. package/bundle/boards/current-time-board.json +32 -0
  20. package/bundle/boards/debounce-demo-board.json +43 -0
  21. package/bundle/boards/decrypt-demo-board.json +47 -0
  22. package/bundle/boards/delay-demo-board.json +28 -0
  23. package/bundle/boards/detect-demo-board.json +64 -0
  24. package/bundle/boards/document-extract-demo-board.json +55 -0
  25. package/bundle/boards/dropitapp-board.json +138 -0
  26. package/bundle/boards/encode-demo-board.json +39 -0
  27. package/bundle/boards/encrypt-board.json +185 -0
  28. package/bundle/boards/encrypt-demo-board.json +39 -0
  29. package/bundle/boards/face-alert-board.json +181 -0
  30. package/bundle/boards/fetcher-demo-board.json +40 -0
  31. package/bundle/boards/fft-demo-board.json +28 -0
  32. package/bundle/boards/filter-demo-board.json +55 -0
  33. package/bundle/boards/flat-map-demo-board.json +42 -0
  34. package/bundle/boards/frame-limit-test-board.json +130 -0
  35. package/bundle/boards/game-board.json +413 -0
  36. package/bundle/boards/game-of-life-board.json +139 -0
  37. package/bundle/boards/game-of-life-demo-board.json +34 -0
  38. package/bundle/boards/gather-demo-board.json +62 -0
  39. package/bundle/boards/group-by-demo-board.json +62 -0
  40. package/bundle/boards/hacker-demo-board.json +45 -0
  41. package/bundle/boards/hacker-news-board.json +741 -0
  42. package/bundle/boards/hash-demo-board.json +40 -0
  43. package/bundle/boards/health-log-browser-demo-board.json +537 -0
  44. package/bundle/boards/health-log-demo-board.json +498 -0
  45. package/bundle/boards/helloworld-board.json +57 -0
  46. package/bundle/boards/hold-demo-board.json +67 -0
  47. package/bundle/boards/hold-scopes-demo-board.json +141 -0
  48. package/bundle/boards/http-client-browser-demo-board.json +379 -0
  49. package/bundle/boards/http-client-demo-board.json +380 -0
  50. package/bundle/boards/image-picker-demo-board.json +22 -0
  51. package/bundle/boards/imap-email-demo-board.json +35 -0
  52. package/bundle/boards/injector-demo-board.json +55 -0
  53. package/bundle/boards/iterator-demo-board.json +55 -0
  54. package/bundle/boards/limit-demo-board.json +66 -0
  55. package/bundle/boards/link-debugger.json +32 -0
  56. package/bundle/boards/live-location-demo-board.json +93 -0
  57. package/bundle/boards/live-radio-cloud-demo-board.json +216 -0
  58. package/bundle/boards/live-radio-cloud-direct-demo-board.json +311 -0
  59. package/bundle/boards/live-radio-demo-board.json +211 -0
  60. package/bundle/boards/live-radio-members-demo-board.json +314 -0
  61. package/bundle/boards/local-storage-demo-board.json +30 -0
  62. package/bundle/boards/lz-compress-demo-board.json +52 -0
  63. package/bundle/boards/map-demo-board.json +46 -0
  64. package/bundle/boards/match-filter-demo-board.json +43 -0
  65. package/bundle/boards/meeting-poll-browser-demo-board.json +649 -0
  66. package/bundle/boards/meeting-poll-demo-board.json +650 -0
  67. package/bundle/boards/microphone-monitor-demo-board.json +28 -0
  68. package/bundle/boards/microphone-speaker-demo-board.json +86 -0
  69. package/bundle/boards/monitor-demo-board.json +52 -0
  70. package/bundle/boards/mounted-endpoint-demo-board-hkp-rt.json +84 -0
  71. package/bundle/boards/mounted-endpoint-demo-board.json +84 -0
  72. package/bundle/boards/nested-rhythm-demo-board.json +1160 -0
  73. package/bundle/boards/next-bus-board.json +52 -0
  74. package/bundle/boards/next-bus-switch-board.json +79 -0
  75. package/bundle/boards/night-groove-demo-board.json +742 -0
  76. package/bundle/boards/noise-alert-board.json +146 -0
  77. package/bundle/boards/offer-followup-demo-board.json +291 -0
  78. package/bundle/boards/offer-intake-demo-board.json +289 -0
  79. package/bundle/boards/offer-intake-hetzner-demo-board.json +286 -0
  80. package/bundle/boards/offer-intake-imap-demo-board.json +289 -0
  81. package/bundle/boards/offer-intake-imap-hetzner-demo-board.json +354 -0
  82. package/bundle/boards/p2p-receiver-demo-board.json +65 -0
  83. package/bundle/boards/p2p-sender-demo-board.json +94 -0
  84. package/bundle/boards/pad-groove-demo-board.json +644 -0
  85. package/bundle/boards/peer-chat-board.json +109 -0
  86. package/bundle/boards/peer-chat-node-board.json +97 -0
  87. package/bundle/boards/qr-code-demo-board.json +22 -0
  88. package/bundle/boards/queue-demo-board.json +239 -0
  89. package/bundle/boards/reduce-demo-board.json +54 -0
  90. package/bundle/boards/remote-named-demo-board-hkp-rt.json +61 -0
  91. package/bundle/boards/remote-named-demo-board.json +61 -0
  92. package/bundle/boards/rss-demo-board.json +530 -0
  93. package/bundle/boards/rss-radio-board.json +515 -0
  94. package/bundle/boards/rss-radio-brief-one-board.json +237 -0
  95. package/bundle/boards/rss-radio-editor-unit-board.json +555 -0
  96. package/bundle/boards/rss-radio-library-unit-board.json +293 -0
  97. package/bundle/boards/rss-radio-unit-board.json +809 -0
  98. package/bundle/boards/rss-radio-voice-unit-board.json +146 -0
  99. package/bundle/boards/runtime-configs/hold-example.json +41 -0
  100. package/bundle/boards/runtime-configs/injector-example.json +23 -0
  101. package/bundle/boards/runtime-configs/speech-to-text-example.json +35 -0
  102. package/bundle/boards/runtime-configs/text-generation-example.json +31 -0
  103. package/bundle/boards/runtime-configs/text-to-speech-example.json +28 -0
  104. package/bundle/boards/runtime-configs/text-to-speech-inflect-example.json +28 -0
  105. package/bundle/boards/runtime-configs/ws-audio-playback-example.json +23 -0
  106. package/bundle/boards/select-demo-board.json +32 -0
  107. package/bundle/boards/send-ntfy-board.json +52 -0
  108. package/bundle/boards/shared-costs-demo-board.json +361 -0
  109. package/bundle/boards/sign-demo-board.json +41 -0
  110. package/bundle/boards/skill-router-demo-board.json +210 -0
  111. package/bundle/boards/smooth-demo-board.json +91 -0
  112. package/bundle/boards/smtp-email-demo-board.json +34 -0
  113. package/bundle/boards/sort-demo-board.json +55 -0
  114. package/bundle/boards/sound-demo-board.json +65 -0
  115. package/bundle/boards/spectral-modifier-board.json +98 -0
  116. package/bundle/boards/speech-synth-demo-board.json +37 -0
  117. package/bundle/boards/speech-to-text-demo-board.json +146 -0
  118. package/bundle/boards/spotify-board.json +75 -0
  119. package/bundle/boards/spread-demo-board.json +35 -0
  120. package/bundle/boards/sql-demo-board.json +56 -0
  121. package/bundle/boards/sql-explorer-board.json +447 -0
  122. package/bundle/boards/sql-explorer-node-board.json +474 -0
  123. package/bundle/boards/sql-import-board.json +156 -0
  124. package/bundle/boards/state-demo-board.json +65 -0
  125. package/bundle/boards/stopper-demo-board.json +40 -0
  126. package/bundle/boards/storage-demo-board.json +193 -0
  127. package/bundle/boards/store-demo-board.json +63 -0
  128. package/bundle/boards/swimlanes-demo-board.json +197 -0
  129. package/bundle/boards/switch-demo-board.json +51 -0
  130. package/bundle/boards/syn-board.json +19 -0
  131. package/bundle/boards/syn-booking-unit-board.json +998 -0
  132. package/bundle/boards/syn-conversations-anthropic-demo-board.json +925 -0
  133. package/bundle/boards/syn-conversations-demo-board.json +925 -0
  134. package/bundle/boards/syn-hotels-unit-board.json +287 -0
  135. package/bundle/boards/syn-mail-desk-board.json +25 -0
  136. package/bundle/boards/syn-mail-desk-unit-board.json +254 -0
  137. package/bundle/boards/telegram-listener-demo-board.json +31 -0
  138. package/bundle/boards/text-generation-anthropic-demo-board.json +66 -0
  139. package/bundle/boards/text-generation-demo-board.json +51 -0
  140. package/bundle/boards/text-generation-local-demo-board.json +80 -0
  141. package/bundle/boards/text-to-speech-demo-board.json +58 -0
  142. package/bundle/boards/timeline-demo-board.json +477 -0
  143. package/bundle/boards/timer-demo-board.json +35 -0
  144. package/bundle/boards/tracks-demo-board.json +95 -0
  145. package/bundle/boards/trigger-pad-demo-board.json +47 -0
  146. package/bundle/boards/triggerpad-board.json +31 -0
  147. package/bundle/boards/triggerpad-recorder-board.json +56 -0
  148. package/bundle/boards/uuid-generator-demo-board.json +166 -0
  149. package/bundle/boards/voice-assistant-demo-board.json +230 -0
  150. package/bundle/boards/voice-assistant-hkp-rt-demo-board.json +239 -0
  151. package/bundle/boards/voice-assistant-local-demo-board.json +232 -0
  152. package/bundle/boards/voice-assistant-skills-demo-board.json +316 -0
  153. package/bundle/boards/voice-assistant-skills-local-demo-board.json +316 -0
  154. package/bundle/boards/xy-pad-demo-board.json +36 -0
  155. package/bundle/docs/content/board-json.md +277 -0
  156. package/bundle/docs/content/boards/alpaca-board.md +56 -0
  157. package/bundle/docs/content/boards/animate-board.md +40 -0
  158. package/bundle/docs/content/boards/ascii-cam-board.md +37 -0
  159. package/bundle/docs/content/boards/audiolize-board.md +47 -0
  160. package/bundle/docs/content/boards/court-booking-browser-demo-board.md +43 -0
  161. package/bundle/docs/content/boards/court-booking-demo-board.md +120 -0
  162. package/bundle/docs/content/boards/current-time-board.md +32 -0
  163. package/bundle/docs/content/boards/dropitapp-board.md +57 -0
  164. package/bundle/docs/content/boards/encrypt-board.md +36 -0
  165. package/bundle/docs/content/boards/face-alert-board.md +50 -0
  166. package/bundle/docs/content/boards/game-board.md +69 -0
  167. package/bundle/docs/content/boards/game-of-life-board.md +47 -0
  168. package/bundle/docs/content/boards/hacker-news-board.md +76 -0
  169. package/bundle/docs/content/boards/health-log-browser-demo-board.md +56 -0
  170. package/bundle/docs/content/boards/health-log-demo-board.md +138 -0
  171. package/bundle/docs/content/boards/helloworld-board.md +40 -0
  172. package/bundle/docs/content/boards/link-debugger.md +31 -0
  173. package/bundle/docs/content/boards/live-radio-cloud-demo-board.md +70 -0
  174. package/bundle/docs/content/boards/live-radio-cloud-direct-demo-board.md +89 -0
  175. package/bundle/docs/content/boards/live-radio-demo-board.md +102 -0
  176. package/bundle/docs/content/boards/live-radio-members-demo-board.md +91 -0
  177. package/bundle/docs/content/boards/meeting-poll-browser-demo-board.md +45 -0
  178. package/bundle/docs/content/boards/meeting-poll-demo-board.md +121 -0
  179. package/bundle/docs/content/boards/mounted-endpoint-demo-board-hkp-rt.md +50 -0
  180. package/bundle/docs/content/boards/nested-rhythm-demo-board.md +165 -0
  181. package/bundle/docs/content/boards/next-bus-board.md +38 -0
  182. package/bundle/docs/content/boards/next-bus-switch-board.md +44 -0
  183. package/bundle/docs/content/boards/night-groove-demo-board.md +110 -0
  184. package/bundle/docs/content/boards/noise-alert-board.md +44 -0
  185. package/bundle/docs/content/boards/pad-groove-demo-board.md +93 -0
  186. package/bundle/docs/content/boards/peer-chat-board.md +49 -0
  187. package/bundle/docs/content/boards/peer-chat-node-board.md +47 -0
  188. package/bundle/docs/content/boards/rss-radio-board.md +221 -0
  189. package/bundle/docs/content/boards/send-ntfy-board.md +33 -0
  190. package/bundle/docs/content/boards/shared-costs-demo-board.md +65 -0
  191. package/bundle/docs/content/boards/spectral-modifier-board.md +55 -0
  192. package/bundle/docs/content/boards/spotify-board.md +46 -0
  193. package/bundle/docs/content/boards/sql-explorer-board.md +70 -0
  194. package/bundle/docs/content/boards/sql-explorer-node-board.md +76 -0
  195. package/bundle/docs/content/boards/sql-import-board.md +37 -0
  196. package/bundle/docs/content/boards/swimlanes-demo-board.md +148 -0
  197. package/bundle/docs/content/boards/syn-mail-desk-board.md +52 -0
  198. package/bundle/docs/content/boards/timeline-demo-board.md +115 -0
  199. package/bundle/docs/content/boards/triggerpad-board.md +32 -0
  200. package/bundle/docs/content/boards/triggerpad-recorder-board.md +52 -0
  201. package/bundle/docs/content/boards/voice-assistant-demo-board.md +51 -0
  202. package/bundle/docs/content/concepts/assets.md +245 -0
  203. package/bundle/docs/content/concepts/blocks.md +300 -0
  204. package/bundle/docs/content/concepts/board-assistant.md +307 -0
  205. package/bundle/docs/content/concepts/board.md +265 -0
  206. package/bundle/docs/content/concepts/cloud-boards.md +803 -0
  207. package/bundle/docs/content/concepts/coordinator.md +297 -0
  208. package/bundle/docs/content/concepts/logging.md +293 -0
  209. package/bundle/docs/content/concepts/mounts.md +314 -0
  210. package/bundle/docs/content/concepts/presets.md +360 -0
  211. package/bundle/docs/content/concepts/remotes.md +423 -0
  212. package/bundle/docs/content/concepts/runtime.md +664 -0
  213. package/bundle/docs/content/concepts/scopes.md +256 -0
  214. package/bundle/docs/content/concepts/service.md +227 -0
  215. package/bundle/docs/content/concepts/units.md +321 -0
  216. package/bundle/docs/content/introduction.md +163 -0
  217. package/bundle/docs/content/llm/circle-text-board.json +55 -0
  218. package/bundle/docs/content/llm/howto-workflow.md +369 -0
  219. package/bundle/docs/content/repository.md +161 -0
  220. package/bundle/docs/content/services/aggregator.md +76 -0
  221. package/bundle/docs/content/services/analyzer.md +44 -0
  222. package/bundle/docs/content/services/ascii-art.md +58 -0
  223. package/bundle/docs/content/services/asset.md +88 -0
  224. package/bundle/docs/content/services/audio-editor.md +57 -0
  225. package/bundle/docs/content/services/audio-encode.md +115 -0
  226. package/bundle/docs/content/services/audio-io.md +173 -0
  227. package/bundle/docs/content/services/batcher.md +49 -0
  228. package/bundle/docs/content/services/board-service.md +48 -0
  229. package/bundle/docs/content/services/browser-sub-service.md +75 -0
  230. package/bundle/docs/content/services/buffer.md +70 -0
  231. package/bundle/docs/content/services/cache.md +92 -0
  232. package/bundle/docs/content/services/camera.md +85 -0
  233. package/bundle/docs/content/services/canvas.md +196 -0
  234. package/bundle/docs/content/services/changes.md +87 -0
  235. package/bundle/docs/content/services/chunked-file-provider.md +63 -0
  236. package/bundle/docs/content/services/communication-dispatcher.md +190 -0
  237. package/bundle/docs/content/services/configurator.md +66 -0
  238. package/bundle/docs/content/services/conversations.md +244 -0
  239. package/bundle/docs/content/services/debounce.md +45 -0
  240. package/bundle/docs/content/services/decrypt.md +53 -0
  241. package/bundle/docs/content/services/delay.md +55 -0
  242. package/bundle/docs/content/services/detect.md +101 -0
  243. package/bundle/docs/content/services/document-extract.md +174 -0
  244. package/bundle/docs/content/services/download.md +67 -0
  245. package/bundle/docs/content/services/encode.md +63 -0
  246. package/bundle/docs/content/services/encrypt.md +53 -0
  247. package/bundle/docs/content/services/fetcher.md +122 -0
  248. package/bundle/docs/content/services/fft.md +96 -0
  249. package/bundle/docs/content/services/file-source.md +67 -0
  250. package/bundle/docs/content/services/filesystem.md +157 -0
  251. package/bundle/docs/content/services/filter.md +133 -0
  252. package/bundle/docs/content/services/flat-map.md +62 -0
  253. package/bundle/docs/content/services/game-of-life.md +93 -0
  254. package/bundle/docs/content/services/gather.md +135 -0
  255. package/bundle/docs/content/services/gif-encoder.md +56 -0
  256. package/bundle/docs/content/services/github.md +85 -0
  257. package/bundle/docs/content/services/group-by.md +54 -0
  258. package/bundle/docs/content/services/hacker.md +79 -0
  259. package/bundle/docs/content/services/hash.md +59 -0
  260. package/bundle/docs/content/services/hold.md +182 -0
  261. package/bundle/docs/content/services/http-relay-client.md +48 -0
  262. package/bundle/docs/content/services/http-uploader.md +62 -0
  263. package/bundle/docs/content/services/http.md +424 -0
  264. package/bundle/docs/content/services/if.md +79 -0
  265. package/bundle/docs/content/services/ifft.md +46 -0
  266. package/bundle/docs/content/services/image-picker.md +50 -0
  267. package/bundle/docs/content/services/imap-email.md +104 -0
  268. package/bundle/docs/content/services/injector.md +129 -0
  269. package/bundle/docs/content/services/input.md +90 -0
  270. package/bundle/docs/content/services/iterator.md +186 -0
  271. package/bundle/docs/content/services/join.md +153 -0
  272. package/bundle/docs/content/services/limit.md +47 -0
  273. package/bundle/docs/content/services/local-storage.md +47 -0
  274. package/bundle/docs/content/services/looper.md +62 -0
  275. package/bundle/docs/content/services/lz-compress.md +52 -0
  276. package/bundle/docs/content/services/map.md +257 -0
  277. package/bundle/docs/content/services/match-filter.md +38 -0
  278. package/bundle/docs/content/services/microphone-monitor.md +66 -0
  279. package/bundle/docs/content/services/monitor.md +67 -0
  280. package/bundle/docs/content/services/ollama.md +116 -0
  281. package/bundle/docs/content/services/openai-prompt.md +74 -0
  282. package/bundle/docs/content/services/output.md +107 -0
  283. package/bundle/docs/content/services/peer-socket.md +61 -0
  284. package/bundle/docs/content/services/qr-code.md +48 -0
  285. package/bundle/docs/content/services/queue.md +201 -0
  286. package/bundle/docs/content/services/reduce.md +51 -0
  287. package/bundle/docs/content/services/rss.md +232 -0
  288. package/bundle/docs/content/services/select.md +47 -0
  289. package/bundle/docs/content/services/sign.md +53 -0
  290. package/bundle/docs/content/services/skill-router.md +154 -0
  291. package/bundle/docs/content/services/smooth.md +59 -0
  292. package/bundle/docs/content/services/smtp-email.md +129 -0
  293. package/bundle/docs/content/services/sort.md +48 -0
  294. package/bundle/docs/content/services/sound.md +87 -0
  295. package/bundle/docs/content/services/speech-synth.md +46 -0
  296. package/bundle/docs/content/services/speech-to-text.md +172 -0
  297. package/bundle/docs/content/services/spotify.md +77 -0
  298. package/bundle/docs/content/services/spread.md +111 -0
  299. package/bundle/docs/content/services/sql.md +491 -0
  300. package/bundle/docs/content/services/state.md +57 -0
  301. package/bundle/docs/content/services/static.md +47 -0
  302. package/bundle/docs/content/services/stopper.md +55 -0
  303. package/bundle/docs/content/services/storage.md +155 -0
  304. package/bundle/docs/content/services/store.md +255 -0
  305. package/bundle/docs/content/services/sub-service.md +152 -0
  306. package/bundle/docs/content/services/switch.md +67 -0
  307. package/bundle/docs/content/services/telegram-listener.md +76 -0
  308. package/bundle/docs/content/services/text-generation.md +390 -0
  309. package/bundle/docs/content/services/text-to-speech.md +130 -0
  310. package/bundle/docs/content/services/timeline.md +333 -0
  311. package/bundle/docs/content/services/timer.md +113 -0
  312. package/bundle/docs/content/services/tracks.md +207 -0
  313. package/bundle/docs/content/services/trigger-pad.md +68 -0
  314. package/bundle/docs/content/services/uuid-generator.md +48 -0
  315. package/bundle/docs/content/services/wav-reader.md +66 -0
  316. package/bundle/docs/content/services/websocket.md +189 -0
  317. package/bundle/docs/content/services/workflow-board-builder.md +65 -0
  318. package/bundle/docs/content/services/xy-pad.md +60 -0
  319. package/bundle/docs/content/targets.md +434 -0
  320. package/bundle/docs/content/testing.md +263 -0
  321. package/bundle/docs/content/vocabulary.md +171 -0
  322. package/bundle/hkp-frontend/src/runtime/browser/BrowserRegistry.tsx +141 -0
  323. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntime.tsx +202 -0
  324. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeApi.ts +306 -0
  325. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeApp.ts +310 -0
  326. package/bundle/hkp-frontend/src/runtime/browser/BrowserRuntimeScope.ts +500 -0
  327. package/bundle/hkp-frontend/src/runtime/browser/UIRegistry.ts +150 -0
  328. package/bundle/hkp-frontend/src/runtime/browser/assetResolver.ts +123 -0
  329. package/bundle/hkp-frontend/src/runtime/browser/pipelineNames.ts +65 -0
  330. package/bundle/hkp-frontend/src/runtime/browser/registry/Default.ts +237 -0
  331. package/bundle/hkp-frontend/src/runtime/browser/services/Aggregator.ts +127 -0
  332. package/bundle/hkp-frontend/src/runtime/browser/services/AggregatorUI.tsx +83 -0
  333. package/bundle/hkp-frontend/src/runtime/browser/services/Analyzer.tsx +43 -0
  334. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/Bars.tsx +33 -0
  335. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/HorizontalSpectrogram.tsx +53 -0
  336. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/VerticalSpectogram.tsx +56 -0
  337. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/Waveform.tsx +109 -0
  338. package/bundle/hkp-frontend/src/runtime/browser/services/AnalyzerUI/index.tsx +99 -0
  339. package/bundle/hkp-frontend/src/runtime/browser/services/AsciiArt.ts +119 -0
  340. package/bundle/hkp-frontend/src/runtime/browser/services/AsciiArtUI.tsx +131 -0
  341. package/bundle/hkp-frontend/src/runtime/browser/services/Asset.ts +125 -0
  342. package/bundle/hkp-frontend/src/runtime/browser/services/AssetUI.tsx +37 -0
  343. package/bundle/hkp-frontend/src/runtime/browser/services/AudioDeviceSettings.tsx +56 -0
  344. package/bundle/hkp-frontend/src/runtime/browser/services/AudioEditor.ts +129 -0
  345. package/bundle/hkp-frontend/src/runtime/browser/services/AudioEditorUI.tsx +549 -0
  346. package/bundle/hkp-frontend/src/runtime/browser/services/AudioInput.ts +298 -0
  347. package/bundle/hkp-frontend/src/runtime/browser/services/AudioInputUI.tsx +257 -0
  348. package/bundle/hkp-frontend/src/runtime/browser/services/AudioOutput.ts +189 -0
  349. package/bundle/hkp-frontend/src/runtime/browser/services/AudioOutputUI.tsx +63 -0
  350. package/bundle/hkp-frontend/src/runtime/browser/services/Batcher.ts +11 -0
  351. package/bundle/hkp-frontend/src/runtime/browser/services/BoardService.tsx +86 -0
  352. package/bundle/hkp-frontend/src/runtime/browser/services/BoardServiceUI.tsx +410 -0
  353. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserGather.ts +311 -0
  354. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserIterator.ts +167 -0
  355. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserSubService.tsx +583 -0
  356. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserSubServiceUI.tsx +187 -0
  357. package/bundle/hkp-frontend/src/runtime/browser/services/BrowserTracks.tsx +477 -0
  358. package/bundle/hkp-frontend/src/runtime/browser/services/Buffer.ts +11 -0
  359. package/bundle/hkp-frontend/src/runtime/browser/services/Cache.ts +134 -0
  360. package/bundle/hkp-frontend/src/runtime/browser/services/CacheUI.tsx +125 -0
  361. package/bundle/hkp-frontend/src/runtime/browser/services/Camera.ts +90 -0
  362. package/bundle/hkp-frontend/src/runtime/browser/services/CameraUI.tsx +321 -0
  363. package/bundle/hkp-frontend/src/runtime/browser/services/Canvas.ts +139 -0
  364. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/canvasDraw.ts +543 -0
  365. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/canvasUtils.ts +39 -0
  366. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/index.tsx +287 -0
  367. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/canvasDraw.test.ts +355 -0
  368. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/canvasUtils.test.ts +89 -0
  369. package/bundle/hkp-frontend/src/runtime/browser/services/CanvasUI/tests/fullscreen.test.tsx +26 -0
  370. package/bundle/hkp-frontend/src/runtime/browser/services/Changes.ts +201 -0
  371. package/bundle/hkp-frontend/src/runtime/browser/services/ChangesUI.tsx +85 -0
  372. package/bundle/hkp-frontend/src/runtime/browser/services/ChunkedFileProvider.tsx +183 -0
  373. package/bundle/hkp-frontend/src/runtime/browser/services/Configurator.ts +258 -0
  374. package/bundle/hkp-frontend/src/runtime/browser/services/ConfiguratorUI.tsx +83 -0
  375. package/bundle/hkp-frontend/src/runtime/browser/services/ConsideredHacker.tsx +28 -0
  376. package/bundle/hkp-frontend/src/runtime/browser/services/Debounce.ts +75 -0
  377. package/bundle/hkp-frontend/src/runtime/browser/services/DebounceUI.tsx +70 -0
  378. package/bundle/hkp-frontend/src/runtime/browser/services/Decrypt.ts +127 -0
  379. package/bundle/hkp-frontend/src/runtime/browser/services/DecryptUI.tsx +39 -0
  380. package/bundle/hkp-frontend/src/runtime/browser/services/Delay.tsx +110 -0
  381. package/bundle/hkp-frontend/src/runtime/browser/services/Detect.ts +214 -0
  382. package/bundle/hkp-frontend/src/runtime/browser/services/DetectUI.tsx +86 -0
  383. package/bundle/hkp-frontend/src/runtime/browser/services/Download.ts +120 -0
  384. package/bundle/hkp-frontend/src/runtime/browser/services/DownloadUI.tsx +61 -0
  385. package/bundle/hkp-frontend/src/runtime/browser/services/Encode.ts +138 -0
  386. package/bundle/hkp-frontend/src/runtime/browser/services/EncodeUI.tsx +52 -0
  387. package/bundle/hkp-frontend/src/runtime/browser/services/Encrypt.ts +125 -0
  388. package/bundle/hkp-frontend/src/runtime/browser/services/EncryptUI.tsx +39 -0
  389. package/bundle/hkp-frontend/src/runtime/browser/services/FFT.tsx +238 -0
  390. package/bundle/hkp-frontend/src/runtime/browser/services/FFTUI.tsx +112 -0
  391. package/bundle/hkp-frontend/src/runtime/browser/services/FeedbackService.ts +247 -0
  392. package/bundle/hkp-frontend/src/runtime/browser/services/FeedbackServiceUI.tsx +35 -0
  393. package/bundle/hkp-frontend/src/runtime/browser/services/Fetcher.tsx +232 -0
  394. package/bundle/hkp-frontend/src/runtime/browser/services/FetcherUI.tsx +154 -0
  395. package/bundle/hkp-frontend/src/runtime/browser/services/FileSource.tsx +171 -0
  396. package/bundle/hkp-frontend/src/runtime/browser/services/Filter.tsx +18 -0
  397. package/bundle/hkp-frontend/src/runtime/browser/services/FilterUI.tsx +89 -0
  398. package/bundle/hkp-frontend/src/runtime/browser/services/FlatMap.ts +68 -0
  399. package/bundle/hkp-frontend/src/runtime/browser/services/FlatMapUI.tsx +38 -0
  400. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLife.ts +210 -0
  401. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeRenderer.ts +182 -0
  402. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeRendererUI.tsx +48 -0
  403. package/bundle/hkp-frontend/src/runtime/browser/services/GameOfLifeUI.tsx +58 -0
  404. package/bundle/hkp-frontend/src/runtime/browser/services/GatherUI.tsx +84 -0
  405. package/bundle/hkp-frontend/src/runtime/browser/services/GifEncoder.tsx +651 -0
  406. package/bundle/hkp-frontend/src/runtime/browser/services/GithubAPI.ts +294 -0
  407. package/bundle/hkp-frontend/src/runtime/browser/services/GithubComponents.tsx +389 -0
  408. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSink.tsx +109 -0
  409. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSinkUI.tsx +143 -0
  410. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSource.tsx +86 -0
  411. package/bundle/hkp-frontend/src/runtime/browser/services/GithubSourceUI.tsx +162 -0
  412. package/bundle/hkp-frontend/src/runtime/browser/services/GroupBy.ts +11 -0
  413. package/bundle/hkp-frontend/src/runtime/browser/services/HTTPUploader.ts +102 -0
  414. package/bundle/hkp-frontend/src/runtime/browser/services/Hacker.ts +73 -0
  415. package/bundle/hkp-frontend/src/runtime/browser/services/HackerUI.tsx +134 -0
  416. package/bundle/hkp-frontend/src/runtime/browser/services/Hash.ts +134 -0
  417. package/bundle/hkp-frontend/src/runtime/browser/services/HashUI.tsx +45 -0
  418. package/bundle/hkp-frontend/src/runtime/browser/services/Hold.ts +288 -0
  419. package/bundle/hkp-frontend/src/runtime/browser/services/HoldUI.tsx +43 -0
  420. package/bundle/hkp-frontend/src/runtime/browser/services/HttpClient.ts +558 -0
  421. package/bundle/hkp-frontend/src/runtime/browser/services/HttpClientUI.tsx +212 -0
  422. package/bundle/hkp-frontend/src/runtime/browser/services/HttpUploaderTokenInjector.ts +149 -0
  423. package/bundle/hkp-frontend/src/runtime/browser/services/IfService.ts +231 -0
  424. package/bundle/hkp-frontend/src/runtime/browser/services/IfServiceUI.tsx +50 -0
  425. package/bundle/hkp-frontend/src/runtime/browser/services/ImagePicker.tsx +118 -0
  426. package/bundle/hkp-frontend/src/runtime/browser/services/Injector.ts +61 -0
  427. package/bundle/hkp-frontend/src/runtime/browser/services/InjectorUI.tsx +389 -0
  428. package/bundle/hkp-frontend/src/runtime/browser/services/Input.ts +214 -0
  429. package/bundle/hkp-frontend/src/runtime/browser/services/InputUI.tsx +71 -0
  430. package/bundle/hkp-frontend/src/runtime/browser/services/IteratorUI.tsx +59 -0
  431. package/bundle/hkp-frontend/src/runtime/browser/services/LZCompress.ts +63 -0
  432. package/bundle/hkp-frontend/src/runtime/browser/services/Limit.ts +39 -0
  433. package/bundle/hkp-frontend/src/runtime/browser/services/LimitUI.tsx +41 -0
  434. package/bundle/hkp-frontend/src/runtime/browser/services/LocalStorage.ts +65 -0
  435. package/bundle/hkp-frontend/src/runtime/browser/services/LocalStorageUI.tsx +72 -0
  436. package/bundle/hkp-frontend/src/runtime/browser/services/Map.ts +14 -0
  437. package/bundle/hkp-frontend/src/runtime/browser/services/MapUI.tsx +334 -0
  438. package/bundle/hkp-frontend/src/runtime/browser/services/MapUIModeAssist.tsx +61 -0
  439. package/bundle/hkp-frontend/src/runtime/browser/services/MatchFilter.ts +11 -0
  440. package/bundle/hkp-frontend/src/runtime/browser/services/MicrophoneMonitor.ts +190 -0
  441. package/bundle/hkp-frontend/src/runtime/browser/services/MicrophoneMonitorUI.tsx +94 -0
  442. package/bundle/hkp-frontend/src/runtime/browser/services/Monitor.tsx +15 -0
  443. package/bundle/hkp-frontend/src/runtime/browser/services/MonitorUI.tsx +281 -0
  444. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPrompt.ts +237 -0
  445. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/BusyIndicator.tsx +18 -0
  446. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/PromptInput.tsx +71 -0
  447. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/StreamingPreview.tsx +24 -0
  448. package/bundle/hkp-frontend/src/runtime/browser/services/OllamaPromptUI/index.tsx +156 -0
  449. package/bundle/hkp-frontend/src/runtime/browser/services/OpenAIPrompt.ts +254 -0
  450. package/bundle/hkp-frontend/src/runtime/browser/services/OpenAIPromptUI.tsx +189 -0
  451. package/bundle/hkp-frontend/src/runtime/browser/services/Output.tsx +145 -0
  452. package/bundle/hkp-frontend/src/runtime/browser/services/OutputUI.tsx +118 -0
  453. package/bundle/hkp-frontend/src/runtime/browser/services/PeerChatTemplate.json +43 -0
  454. package/bundle/hkp-frontend/src/runtime/browser/services/PeerConnection.ts +260 -0
  455. package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocket.tsx +268 -0
  456. package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocketReceiverTemplate.json +29 -0
  457. package/bundle/hkp-frontend/src/runtime/browser/services/PeerSocketUI.tsx +341 -0
  458. package/bundle/hkp-frontend/src/runtime/browser/services/PlaceholderUI.tsx +72 -0
  459. package/bundle/hkp-frontend/src/runtime/browser/services/QrCode.ts +63 -0
  460. package/bundle/hkp-frontend/src/runtime/browser/services/QrCodeUI.tsx +197 -0
  461. package/bundle/hkp-frontend/src/runtime/browser/services/Select.ts +40 -0
  462. package/bundle/hkp-frontend/src/runtime/browser/services/SelectUI.tsx +41 -0
  463. package/bundle/hkp-frontend/src/runtime/browser/services/ServiceBase.ts +50 -0
  464. package/bundle/hkp-frontend/src/runtime/browser/services/SetRuntimeVariable.ts +65 -0
  465. package/bundle/hkp-frontend/src/runtime/browser/services/SetRuntimeVariableUI.tsx +50 -0
  466. package/bundle/hkp-frontend/src/runtime/browser/services/Sign.ts +182 -0
  467. package/bundle/hkp-frontend/src/runtime/browser/services/SignUI.tsx +55 -0
  468. package/bundle/hkp-frontend/src/runtime/browser/services/Smooth.ts +101 -0
  469. package/bundle/hkp-frontend/src/runtime/browser/services/SmoothUI.tsx +50 -0
  470. package/bundle/hkp-frontend/src/runtime/browser/services/Sort.ts +59 -0
  471. package/bundle/hkp-frontend/src/runtime/browser/services/SortUI.tsx +61 -0
  472. package/bundle/hkp-frontend/src/runtime/browser/services/Sound.ts +541 -0
  473. package/bundle/hkp-frontend/src/runtime/browser/services/SoundUI.tsx +183 -0
  474. package/bundle/hkp-frontend/src/runtime/browser/services/SpeechSynth.ts +56 -0
  475. package/bundle/hkp-frontend/src/runtime/browser/services/SpeechSynthUI.tsx +108 -0
  476. package/bundle/hkp-frontend/src/runtime/browser/services/Spotify.tsx +111 -0
  477. package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyAPI.ts +113 -0
  478. package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyComponents.tsx +104 -0
  479. package/bundle/hkp-frontend/src/runtime/browser/services/SpotifyUI.tsx +186 -0
  480. package/bundle/hkp-frontend/src/runtime/browser/services/Spread.ts +117 -0
  481. package/bundle/hkp-frontend/src/runtime/browser/services/SpreadUI.tsx +38 -0
  482. package/bundle/hkp-frontend/src/runtime/browser/services/Sql.ts +448 -0
  483. package/bundle/hkp-frontend/src/runtime/browser/services/SqlInspector.tsx +332 -0
  484. package/bundle/hkp-frontend/src/runtime/browser/services/SqlUI.tsx +226 -0
  485. package/bundle/hkp-frontend/src/runtime/browser/services/State.ts +149 -0
  486. package/bundle/hkp-frontend/src/runtime/browser/services/Stopper.ts +29 -0
  487. package/bundle/hkp-frontend/src/runtime/browser/services/Switch.tsx +419 -0
  488. package/bundle/hkp-frontend/src/runtime/browser/services/SwitchUI.tsx +171 -0
  489. package/bundle/hkp-frontend/src/runtime/browser/services/TickRuleDelta.ts +101 -0
  490. package/bundle/hkp-frontend/src/runtime/browser/services/TickRuleDeltaUI.tsx +56 -0
  491. package/bundle/hkp-frontend/src/runtime/browser/services/Timeline.ts +709 -0
  492. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/TimelinePanel.tsx +79 -0
  493. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/TimelineRows.tsx +574 -0
  494. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/Transport.tsx +141 -0
  495. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/index.tsx +119 -0
  496. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/model.ts +425 -0
  497. package/bundle/hkp-frontend/src/runtime/browser/services/TimelineUI/parts.tsx +708 -0
  498. package/bundle/hkp-frontend/src/runtime/browser/services/Timer.ts +15 -0
  499. package/bundle/hkp-frontend/src/runtime/browser/services/TimerUI.tsx +213 -0
  500. package/bundle/hkp-frontend/src/runtime/browser/services/TracksUI.tsx +81 -0
  501. package/bundle/hkp-frontend/src/runtime/browser/services/TriggerPad.ts +108 -0
  502. package/bundle/hkp-frontend/src/runtime/browser/services/TriggerPadUI.tsx +160 -0
  503. package/bundle/hkp-frontend/src/runtime/browser/services/UuidGenerator.ts +74 -0
  504. package/bundle/hkp-frontend/src/runtime/browser/services/UuidGeneratorUI.tsx +59 -0
  505. package/bundle/hkp-frontend/src/runtime/browser/services/WaveformDisplay.tsx +104 -0
  506. package/bundle/hkp-frontend/src/runtime/browser/services/WebsocketClient.ts +114 -0
  507. package/bundle/hkp-frontend/src/runtime/browser/services/WebsocketClientUI.tsx +42 -0
  508. package/bundle/hkp-frontend/src/runtime/browser/services/WorkflowBoardBuilder.ts +499 -0
  509. package/bundle/hkp-frontend/src/runtime/browser/services/WorkflowBoardBuilderUI.tsx +521 -0
  510. package/bundle/hkp-frontend/src/runtime/browser/services/XYPad.ts +68 -0
  511. package/bundle/hkp-frontend/src/runtime/browser/services/XYPadUI.tsx +274 -0
  512. package/bundle/hkp-frontend/src/runtime/browser/services/audio/audioHelper.ts +36 -0
  513. package/bundle/hkp-frontend/src/runtime/browser/services/base/Batcher.ts +76 -0
  514. package/bundle/hkp-frontend/src/runtime/browser/services/base/Buffer.ts +142 -0
  515. package/bundle/hkp-frontend/src/runtime/browser/services/base/Filter.ts +125 -0
  516. package/bundle/hkp-frontend/src/runtime/browser/services/base/GroupBy.ts +101 -0
  517. package/bundle/hkp-frontend/src/runtime/browser/services/base/Map.ts +543 -0
  518. package/bundle/hkp-frontend/src/runtime/browser/services/base/MatchFilter.ts +49 -0
  519. package/bundle/hkp-frontend/src/runtime/browser/services/base/Monitor.ts +75 -0
  520. package/bundle/hkp-frontend/src/runtime/browser/services/base/Reduce.ts +74 -0
  521. package/bundle/hkp-frontend/src/runtime/browser/services/base/Timer.ts +342 -0
  522. package/bundle/hkp-frontend/src/runtime/browser/services/base/bundle.js +7375 -0
  523. package/bundle/hkp-frontend/src/runtime/browser/services/base/eval.ts +208 -0
  524. package/bundle/hkp-frontend/src/runtime/browser/services/base/expressionEval.ts +223 -0
  525. package/bundle/hkp-frontend/src/runtime/browser/services/base/helpers.ts +10 -0
  526. package/bundle/hkp-frontend/src/runtime/browser/services/base/index.ts +37 -0
  527. package/bundle/hkp-frontend/src/runtime/browser/services/camera/videoCapture.ts +78 -0
  528. package/bundle/hkp-frontend/src/runtime/browser/services/changes-modes.ts +9 -0
  529. package/bundle/hkp-frontend/src/runtime/browser/services/colorpalette.ts +26 -0
  530. package/bundle/hkp-frontend/src/runtime/browser/services/detect/DetectionPreview.tsx +76 -0
  531. package/bundle/hkp-frontend/src/runtime/browser/services/detect/mediapipe.ts +34 -0
  532. package/bundle/hkp-frontend/src/runtime/browser/services/detect/models/README.md +14 -0
  533. package/bundle/hkp-frontend/src/runtime/browser/services/detect/models/blaze_face_short_range.tflite +0 -0
  534. package/bundle/hkp-frontend/src/runtime/browser/services/detect-modes.ts +7 -0
  535. package/bundle/hkp-frontend/src/runtime/browser/services/encode-modes.ts +10 -0
  536. package/bundle/hkp-frontend/src/runtime/browser/services/helpers.ts +300 -0
  537. package/bundle/hkp-frontend/src/runtime/browser/services/http-client-methods.ts +10 -0
  538. package/bundle/hkp-frontend/src/runtime/browser/services/sql-database.ts +594 -0
  539. package/bundle/hkp-frontend/src/runtime/browser/services/sql-dump.ts +192 -0
  540. package/bundle/hkp-frontend/src/runtime/browser/services/sql-inspect.ts +130 -0
  541. package/bundle/hkp-frontend/src/runtime/browser/services/sql-inspector.css +155 -0
  542. package/bundle/hkp-frontend/src/runtime/browser/services/sql-modes.ts +27 -0
  543. package/bundle/hkp-frontend/src/runtime/browser/services/tests/TESTING_APPROACH.md +169 -0
  544. package/bundle/hkp-frontend/src/runtime/browser/services/tests/__snapshots__/service-ui.future-enhancements.test.tsx.snap +5 -0
  545. package/bundle/hkp-frontend/src/runtime/browser/services/tests/audio-input-permissions.test.ts +42 -0
  546. package/bundle/hkp-frontend/src/runtime/browser/services/tests/audiolizeLanes.test.ts +70 -0
  547. package/bundle/hkp-frontend/src/runtime/browser/services/tests/browser-scopes.test.ts +305 -0
  548. package/bundle/hkp-frontend/src/runtime/browser/services/tests/cache-service.test.ts +53 -0
  549. package/bundle/hkp-frontend/src/runtime/browser/services/tests/camera-video-capture.test.ts +24 -0
  550. package/bundle/hkp-frontend/src/runtime/browser/services/tests/changes-service.test.ts +133 -0
  551. package/bundle/hkp-frontend/src/runtime/browser/services/tests/crypto-secrets.test.ts +196 -0
  552. package/bundle/hkp-frontend/src/runtime/browser/services/tests/detect-service.test.ts +119 -0
  553. package/bundle/hkp-frontend/src/runtime/browser/services/tests/download.test.ts +100 -0
  554. package/bundle/hkp-frontend/src/runtime/browser/services/tests/expressionEval.test.ts +117 -0
  555. package/bundle/hkp-frontend/src/runtime/browser/services/tests/fetcher-panel.test.tsx +35 -0
  556. package/bundle/hkp-frontend/src/runtime/browser/services/tests/fetcher-service.test.ts +80 -0
  557. package/bundle/hkp-frontend/src/runtime/browser/services/tests/filter-service.test.ts +37 -0
  558. package/bundle/hkp-frontend/src/runtime/browser/services/tests/github-secrets.test.ts +108 -0
  559. package/bundle/hkp-frontend/src/runtime/browser/services/tests/group-by-board.test.ts +42 -0
  560. package/bundle/hkp-frontend/src/runtime/browser/services/tests/hold-service.test.ts +199 -0
  561. package/bundle/hkp-frontend/src/runtime/browser/services/tests/http-client-service.test.ts +474 -0
  562. package/bundle/hkp-frontend/src/runtime/browser/services/tests/http-uploader-token-injector.test.ts +152 -0
  563. package/bundle/hkp-frontend/src/runtime/browser/services/tests/iterator-gather-service.test.ts +277 -0
  564. package/bundle/hkp-frontend/src/runtime/browser/services/tests/map-service.test.ts +1047 -0
  565. package/bundle/hkp-frontend/src/runtime/browser/services/tests/map-ui.test.tsx +70 -0
  566. package/bundle/hkp-frontend/src/runtime/browser/services/tests/nested-rhythm-board.test.ts +311 -0
  567. package/bundle/hkp-frontend/src/runtime/browser/services/tests/night-groove-board.test.ts +290 -0
  568. package/bundle/hkp-frontend/src/runtime/browser/services/tests/pad-groove-board.test.ts +230 -0
  569. package/bundle/hkp-frontend/src/runtime/browser/services/tests/peer-host-discovery.test.ts +77 -0
  570. package/bundle/hkp-frontend/src/runtime/browser/services/tests/peer-socket-discovery.test.ts +69 -0
  571. package/bundle/hkp-frontend/src/runtime/browser/services/tests/pipeline-names.test.ts +63 -0
  572. package/bundle/hkp-frontend/src/runtime/browser/services/tests/secret-canary.test.ts +121 -0
  573. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-modules.contract.test.ts +229 -0
  574. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.advanced.test.tsx +670 -0
  575. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.future-enhancements.test.tsx +219 -0
  576. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.integration.test.tsx +432 -0
  577. package/bundle/hkp-frontend/src/runtime/browser/services/tests/service-ui.smoke.test.tsx +140 -0
  578. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sound-service.test.ts +293 -0
  579. package/bundle/hkp-frontend/src/runtime/browser/services/tests/spread-service.test.ts +137 -0
  580. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-dump.test.ts +172 -0
  581. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-inspect.test.ts +163 -0
  582. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql-inspector.test.tsx +121 -0
  583. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sql.test.ts +702 -0
  584. package/bundle/hkp-frontend/src/runtime/browser/services/tests/sub-service-in-block.test.tsx +84 -0
  585. package/bundle/hkp-frontend/src/runtime/browser/services/tests/switch-service.test.ts +254 -0
  586. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-board.test.ts +218 -0
  587. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-service.test.ts +1002 -0
  588. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-ui-model.test.ts +230 -0
  589. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timeline-ui.test.tsx +371 -0
  590. package/bundle/hkp-frontend/src/runtime/browser/services/tests/timer-service.test.ts +902 -0
  591. package/bundle/hkp-frontend/src/runtime/browser/services/tests/tracks-service.test.ts +275 -0
  592. package/bundle/hkp-frontend/src/runtime/browser/services/tests/tracks-ui.test.tsx +126 -0
  593. package/bundle/hkp-frontend/src/runtime/browser/services/tests/triggerpad-recorder-board.test.ts +100 -0
  594. package/bundle/hkp-frontend/src/runtime/browser/services/tests/uuid-generator-service.test.ts +214 -0
  595. package/bundle/hkp-frontend/src/runtime/browser/services/timeline-core.ts +410 -0
  596. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/DefaultWorkflowBoard.ts +90 -0
  597. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/RefinementSession.ts +121 -0
  598. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/SystemPromptCatalog.ts +245 -0
  599. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/catalog/browser-service-specs.json +110 -0
  600. package/bundle/hkp-frontend/src/runtime/browser/services/workflow-prompt/catalog/runtime-capabilities.json +37 -0
  601. package/bundle/hkp-frontend/src/runtime/browser/tests/asset-service.test.ts +73 -0
  602. package/bundle/hkp-frontend/src/runtime/browser/tests/board-persistence.integration.test.tsx +391 -0
  603. package/bundle/hkp-frontend/src/runtime/browser/tests/browser-runtime.identity-binding.test.tsx +81 -0
  604. package/bundle/hkp-frontend/src/runtime/browser/tests/demo-boards.regression.test.tsx +386 -0
  605. package/bundle/hkp-frontend/src/runtime/browser/tests/failed-call-lifecycle.test.ts +56 -0
  606. package/bundle/hkp-frontend/src/runtime/browser/tests/http-client.integration.test.ts +146 -0
  607. package/bundle/hkp-frontend/src/runtime/browser/tests/nested-run.integration.test.ts +415 -0
  608. package/bundle/hkp-frontend/src/runtime/browser/tests/replay-next.test.ts +391 -0
  609. package/bundle/hkp-frontend/src/runtime/browser/tests/rerun.test.ts +71 -0
  610. package/bundle/hkp-frontend/src/runtime/browser/tests/run-no-input.test.ts +72 -0
  611. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-add.integration.test.tsx +256 -0
  612. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-operations.integration.test.tsx +310 -0
  613. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-processing.integration.test.ts +311 -0
  614. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-removal.integration.test.tsx +454 -0
  615. package/bundle/hkp-frontend/src/runtime/browser/tests/runtime-update.identity.integration.test.tsx +145 -0
  616. package/bundle/hkp-frontend/src/runtime/browser/tests/service-operations.integration.test.tsx +511 -0
  617. package/bundle/hkp-node/src/address.ts +72 -0
  618. package/bundle/hkp-node/src/assets.ts +582 -0
  619. package/bundle/hkp-node/src/auth.ts +369 -0
  620. package/bundle/hkp-node/src/callReport.ts +281 -0
  621. package/bundle/hkp-node/src/coordinator/auth.ts +85 -0
  622. package/bundle/hkp-node/src/coordinator/binaryFrame.ts +189 -0
  623. package/bundle/hkp-node/src/coordinator/boardStore.ts +0 -0
  624. package/bundle/hkp-node/src/coordinator/bridge.ts +242 -0
  625. package/bundle/hkp-node/src/coordinator/bridgeProtocol.ts +200 -0
  626. package/bundle/hkp-node/src/coordinator/coordinator.ts +594 -0
  627. package/bundle/hkp-node/src/coordinator/facadeAccess.ts +426 -0
  628. package/bundle/hkp-node/src/coordinator/fileBoardStore.ts +159 -0
  629. package/bundle/hkp-node/src/coordinator/frameLimits.ts +41 -0
  630. package/bundle/hkp-node/src/coordinator/index.ts +12 -0
  631. package/bundle/hkp-node/src/coordinator/join.ts +62 -0
  632. package/bundle/hkp-node/src/coordinator/logStore.ts +335 -0
  633. package/bundle/hkp-node/src/coordinator/members.ts +133 -0
  634. package/bundle/hkp-node/src/coordinator/mount.ts +124 -0
  635. package/bundle/hkp-node/src/coordinator/participantProtocol.ts +169 -0
  636. package/bundle/hkp-node/src/coordinator/participants.ts +666 -0
  637. package/bundle/hkp-node/src/coordinator/router.ts +416 -0
  638. package/bundle/hkp-node/src/coordinator/session.ts +1610 -0
  639. package/bundle/hkp-node/src/coordinator/types.ts +95 -0
  640. package/bundle/hkp-node/src/coordinatorLinks.ts +712 -0
  641. package/bundle/hkp-node/src/credentialedFetch.ts +122 -0
  642. package/bundle/hkp-node/src/egress.ts +344 -0
  643. package/bundle/hkp-node/src/expressionEval.ts +223 -0
  644. package/bundle/hkp-node/src/index.ts +470 -0
  645. package/bundle/hkp-node/src/instance.ts +172 -0
  646. package/bundle/hkp-node/src/mounts.ts +296 -0
  647. package/bundle/hkp-node/src/origins.ts +201 -0
  648. package/bundle/hkp-node/src/reset.ts +187 -0
  649. package/bundle/hkp-node/src/runtime.ts +1345 -0
  650. package/bundle/hkp-node/src/secrets.ts +292 -0
  651. package/bundle/hkp-node/src/server.ts +2120 -0
  652. package/bundle/hkp-node/src/services/asset.ts +150 -0
  653. package/bundle/hkp-node/src/services/claudeModels.ts +370 -0
  654. package/bundle/hkp-node/src/services/communication-dispatcher.ts +735 -0
  655. package/bundle/hkp-node/src/services/conversations.ts +914 -0
  656. package/bundle/hkp-node/src/services/database.ts +386 -0
  657. package/bundle/hkp-node/src/services/document-extract.ts +575 -0
  658. package/bundle/hkp-node/src/services/expression.ts +417 -0
  659. package/bundle/hkp-node/src/services/fileStore.ts +369 -0
  660. package/bundle/hkp-node/src/services/filesystem.ts +280 -0
  661. package/bundle/hkp-node/src/services/gather.ts +335 -0
  662. package/bundle/hkp-node/src/services/hold.ts +275 -0
  663. package/bundle/hkp-node/src/services/http-client.ts +525 -0
  664. package/bundle/hkp-node/src/services/http-server.ts +1222 -0
  665. package/bundle/hkp-node/src/services/imap-email.ts +627 -0
  666. package/bundle/hkp-node/src/services/injector.ts +135 -0
  667. package/bundle/hkp-node/src/services/iterator.ts +203 -0
  668. package/bundle/hkp-node/src/services/join.ts +226 -0
  669. package/bundle/hkp-node/src/services/map.ts +632 -0
  670. package/bundle/hkp-node/src/services/monitor.ts +128 -0
  671. package/bundle/hkp-node/src/services/nested-pipeline.ts +405 -0
  672. package/bundle/hkp-node/src/services/peer-server.ts +268 -0
  673. package/bundle/hkp-node/src/services/queue-store.ts +301 -0
  674. package/bundle/hkp-node/src/services/queue.ts +316 -0
  675. package/bundle/hkp-node/src/services/recordStore.ts +341 -0
  676. package/bundle/hkp-node/src/services/rss-parse.ts +281 -0
  677. package/bundle/hkp-node/src/services/rss.ts +392 -0
  678. package/bundle/hkp-node/src/services/smtp-email.ts +398 -0
  679. package/bundle/hkp-node/src/services/spread.ts +153 -0
  680. package/bundle/hkp-node/src/services/sql-dump.ts +192 -0
  681. package/bundle/hkp-node/src/services/sql.ts +429 -0
  682. package/bundle/hkp-node/src/services/stopper.ts +69 -0
  683. package/bundle/hkp-node/src/services/storage.ts +332 -0
  684. package/bundle/hkp-node/src/services/store.ts +609 -0
  685. package/bundle/hkp-node/src/services/stream.ts +367 -0
  686. package/bundle/hkp-node/src/services/sub-service.ts +600 -0
  687. package/bundle/hkp-node/src/services/telegram-listener.ts +263 -0
  688. package/bundle/hkp-node/src/services/telegram-sender.ts +136 -0
  689. package/bundle/hkp-node/src/services/text-generation.ts +1249 -0
  690. package/bundle/hkp-node/src/services/timer.ts +273 -0
  691. package/bundle/hkp-node/src/services/tracks.ts +381 -0
  692. package/bundle/hkp-node/src/services/websocket-reader.ts +364 -0
  693. package/bundle/hkp-node/src/types.ts +465 -0
  694. package/bundle/hkp-node/src/wsTickets.ts +77 -0
  695. package/bundle/hkp-node/src/yas.ts +95 -0
  696. package/bundle/hkp-python/src/hkp/__init__.py +1 -0
  697. package/bundle/hkp-python/src/hkp/__main__.py +241 -0
  698. package/bundle/hkp-python/src/hkp/address.py +56 -0
  699. package/bundle/hkp-python/src/hkp/assets.py +439 -0
  700. package/bundle/hkp-python/src/hkp/auth.py +252 -0
  701. package/bundle/hkp-python/src/hkp/binary_frame.py +100 -0
  702. package/bundle/hkp-python/src/hkp/call_report.py +201 -0
  703. package/bundle/hkp-python/src/hkp/coordinator_links.py +667 -0
  704. package/bundle/hkp-python/src/hkp/data.py +118 -0
  705. package/bundle/hkp-python/src/hkp/egress.py +310 -0
  706. package/bundle/hkp-python/src/hkp/mount.py +46 -0
  707. package/bundle/hkp-python/src/hkp/mounts.py +288 -0
  708. package/bundle/hkp-python/src/hkp/origins.py +169 -0
  709. package/bundle/hkp-python/src/hkp/runtime.py +1131 -0
  710. package/bundle/hkp-python/src/hkp/secrets.py +261 -0
  711. package/bundle/hkp-python/src/hkp/server.py +1714 -0
  712. package/bundle/hkp-python/src/hkp/services/__init__.py +0 -0
  713. package/bundle/hkp-python/src/hkp/services/asset.py +123 -0
  714. package/bundle/hkp-python/src/hkp/services/audio_encode.py +190 -0
  715. package/bundle/hkp-python/src/hkp/services/expression.py +942 -0
  716. package/bundle/hkp-python/src/hkp/services/gather.py +266 -0
  717. package/bundle/hkp-python/src/hkp/services/hold.py +246 -0
  718. package/bundle/hkp-python/src/hkp/services/http_client.py +444 -0
  719. package/bundle/hkp-python/src/hkp/services/http_server.py +790 -0
  720. package/bundle/hkp-python/src/hkp/services/iterator.py +141 -0
  721. package/bundle/hkp-python/src/hkp/services/join.py +173 -0
  722. package/bundle/hkp-python/src/hkp/services/map_service.py +452 -0
  723. package/bundle/hkp-python/src/hkp/services/monitor.py +99 -0
  724. package/bundle/hkp-python/src/hkp/services/nested_pipeline.py +278 -0
  725. package/bundle/hkp-python/src/hkp/services/skill_router.py +388 -0
  726. package/bundle/hkp-python/src/hkp/services/speech_to_text.py +186 -0
  727. package/bundle/hkp-python/src/hkp/services/spread.py +114 -0
  728. package/bundle/hkp-python/src/hkp/services/stopper.py +59 -0
  729. package/bundle/hkp-python/src/hkp/services/sub_service.py +417 -0
  730. package/bundle/hkp-python/src/hkp/services/text_generation.py +498 -0
  731. package/bundle/hkp-python/src/hkp/services/text_to_speech.py +237 -0
  732. package/bundle/hkp-python/src/hkp/services/timer.py +267 -0
  733. package/bundle/hkp-python/src/hkp/services/tracks.py +251 -0
  734. package/bundle/hkp-python/src/hkp/types.py +412 -0
  735. package/bundle/hkp-python/src/hkp/ws_tickets.py +54 -0
  736. package/bundle/hkp-python/src/hkp/yas.py +192 -0
  737. package/bundle/hkp-rt/lib/CMakeLists.txt +193 -0
  738. package/bundle/hkp-rt/lib/hkp-bundles/CMakeLists.txt +55 -0
  739. package/bundle/hkp-rt/lib/hkp-bundles/plugin_register.cpp +14 -0
  740. package/bundle/hkp-rt/lib/include/app.h +201 -0
  741. package/bundle/hkp-rt/lib/include/assets.h +239 -0
  742. package/bundle/hkp-rt/lib/include/auth.h +167 -0
  743. package/bundle/hkp-rt/lib/include/call_report.h +197 -0
  744. package/bundle/hkp-rt/lib/include/coordinator_links.h +127 -0
  745. package/bundle/hkp-rt/lib/include/discovery_hooks.h +29 -0
  746. package/bundle/hkp-rt/lib/include/egress.h +379 -0
  747. package/bundle/hkp-rt/lib/include/files.h +275 -0
  748. package/bundle/hkp-rt/lib/include/log_entry.h +131 -0
  749. package/bundle/hkp-rt/lib/include/mounts.h +139 -0
  750. package/bundle/hkp-rt/lib/include/origins.h +363 -0
  751. package/bundle/hkp-rt/lib/include/registry.h +119 -0
  752. package/bundle/hkp-rt/lib/include/secrets.h +414 -0
  753. package/bundle/hkp-rt/lib/include/server.h +122 -0
  754. package/bundle/hkp-rt/lib/include/service.h +190 -0
  755. package/bundle/hkp-rt/lib/include/slot_store.h +41 -0
  756. package/bundle/hkp-rt/lib/include/standalone_config.h +253 -0
  757. package/bundle/hkp-rt/lib/include/types/audio.h +3 -0
  758. package/bundle/hkp-rt/lib/include/types/data.h +152 -0
  759. package/bundle/hkp-rt/lib/include/types/message.h +56 -0
  760. package/bundle/hkp-rt/lib/include/types/models.h +154 -0
  761. package/bundle/hkp-rt/lib/include/types/owns_me.h +19 -0
  762. package/bundle/hkp-rt/lib/include/types/ringbuffer.h +86 -0
  763. package/bundle/hkp-rt/lib/include/types/types.h +33 -0
  764. package/bundle/hkp-rt/lib/include/types/validation.h +205 -0
  765. package/bundle/hkp-rt/lib/src/address.h +88 -0
  766. package/bundle/hkp-rt/lib/src/app.cpp +591 -0
  767. package/bundle/hkp-rt/lib/src/assets.cpp +686 -0
  768. package/bundle/hkp-rt/lib/src/binary_frame.h +154 -0
  769. package/bundle/hkp-rt/lib/src/common/expression.h +1481 -0
  770. package/bundle/hkp-rt/lib/src/common/inja.h +36 -0
  771. package/bundle/hkp-rt/lib/src/common/link_socket.cpp +437 -0
  772. package/bundle/hkp-rt/lib/src/common/link_socket.h +97 -0
  773. package/bundle/hkp-rt/lib/src/common/realtime_wakeup.h +120 -0
  774. package/bundle/hkp-rt/lib/src/common/stream_broadcast.h +250 -0
  775. package/bundle/hkp-rt/lib/src/common/string_util.h +31 -0
  776. package/bundle/hkp-rt/lib/src/common/websocket_client_session.cpp +217 -0
  777. package/bundle/hkp-rt/lib/src/common/websocket_client_session.h +37 -0
  778. package/bundle/hkp-rt/lib/src/common/websocket_config.h +119 -0
  779. package/bundle/hkp-rt/lib/src/common/websocket_protocol.h +32 -0
  780. package/bundle/hkp-rt/lib/src/common/websocket_server.cpp +82 -0
  781. package/bundle/hkp-rt/lib/src/common/websocket_server.h +57 -0
  782. package/bundle/hkp-rt/lib/src/common/websocket_server_listener.cpp +115 -0
  783. package/bundle/hkp-rt/lib/src/common/websocket_server_listener.h +35 -0
  784. package/bundle/hkp-rt/lib/src/common/websocket_server_session.cpp +172 -0
  785. package/bundle/hkp-rt/lib/src/common/websocket_server_session.h +53 -0
  786. package/bundle/hkp-rt/lib/src/common.h +13 -0
  787. package/bundle/hkp-rt/lib/src/coordinator_links.cpp +1142 -0
  788. package/bundle/hkp-rt/lib/src/discovery/discovery.cpp +707 -0
  789. package/bundle/hkp-rt/lib/src/discovery/discovery.h +89 -0
  790. package/bundle/hkp-rt/lib/src/http/auth.cpp +569 -0
  791. package/bundle/hkp-rt/lib/src/http/front_door.cpp +518 -0
  792. package/bundle/hkp-rt/lib/src/http/front_door.h +131 -0
  793. package/bundle/hkp-rt/lib/src/http/server.cpp +1539 -0
  794. package/bundle/hkp-rt/lib/src/http/ws_tickets.h +125 -0
  795. package/bundle/hkp-rt/lib/src/mount.h +63 -0
  796. package/bundle/hkp-rt/lib/src/process_context.h +335 -0
  797. package/bundle/hkp-rt/lib/src/process_depth.h +20 -0
  798. package/bundle/hkp-rt/lib/src/registry.cpp +233 -0
  799. package/bundle/hkp-rt/lib/src/runtime.cpp +986 -0
  800. package/bundle/hkp-rt/lib/src/runtime.h +225 -0
  801. package/bundle/hkp-rt/lib/src/runtime_host.h +180 -0
  802. package/bundle/hkp-rt/lib/src/service.cpp +315 -0
  803. package/bundle/hkp-rt/lib/src/services/asset.h +185 -0
  804. package/bundle/hkp-rt/lib/src/services/audio_encode.cpp +372 -0
  805. package/bundle/hkp-rt/lib/src/services/audio_encode.h +97 -0
  806. package/bundle/hkp-rt/lib/src/services/cache.h +362 -0
  807. package/bundle/hkp-rt/lib/src/services/cache_subservices.h +463 -0
  808. package/bundle/hkp-rt/lib/src/services/core_audio.cpp +384 -0
  809. package/bundle/hkp-rt/lib/src/services/core_audio.h +22 -0
  810. package/bundle/hkp-rt/lib/src/services/core_input.h +337 -0
  811. package/bundle/hkp-rt/lib/src/services/core_output.h +370 -0
  812. package/bundle/hkp-rt/lib/src/services/ffmpeg/detail.cpp +749 -0
  813. package/bundle/hkp-rt/lib/src/services/ffmpeg/detail.h +29 -0
  814. package/bundle/hkp-rt/lib/src/services/ffmpeg/ffmpeg.cpp +193 -0
  815. package/bundle/hkp-rt/lib/src/services/ffmpeg/ffmpeg.h +40 -0
  816. package/bundle/hkp-rt/lib/src/services/ffmpeg/types.h +120 -0
  817. package/bundle/hkp-rt/lib/src/services/fft_service.h +190 -0
  818. package/bundle/hkp-rt/lib/src/services/filesystem.h +309 -0
  819. package/bundle/hkp-rt/lib/src/services/filter.h +208 -0
  820. package/bundle/hkp-rt/lib/src/services/gather.h +272 -0
  821. package/bundle/hkp-rt/lib/src/services/hold.h +304 -0
  822. package/bundle/hkp-rt/lib/src/services/http_client.cpp +347 -0
  823. package/bundle/hkp-rt/lib/src/services/http_client.h +67 -0
  824. package/bundle/hkp-rt/lib/src/services/http_client_impl.h +45 -0
  825. package/bundle/hkp-rt/lib/src/services/http_client_template_examples.md +202 -0
  826. package/bundle/hkp-rt/lib/src/services/http_server/http_listener.cpp +130 -0
  827. package/bundle/hkp-rt/lib/src/services/http_server/http_listener.h +33 -0
  828. package/bundle/hkp-rt/lib/src/services/http_server/http_server.cpp +351 -0
  829. package/bundle/hkp-rt/lib/src/services/http_server/http_server.h +79 -0
  830. package/bundle/hkp-rt/lib/src/services/http_server/http_server_impl.cpp +230 -0
  831. package/bundle/hkp-rt/lib/src/services/http_server/http_server_impl.h +64 -0
  832. package/bundle/hkp-rt/lib/src/services/http_server/http_server_subservices.cpp +950 -0
  833. package/bundle/hkp-rt/lib/src/services/http_server/http_server_subservices.h +253 -0
  834. package/bundle/hkp-rt/lib/src/services/http_server/http_session.cpp +495 -0
  835. package/bundle/hkp-rt/lib/src/services/http_server/http_session.h +169 -0
  836. package/bundle/hkp-rt/lib/src/services/http_server/http_stream_listener.cpp +270 -0
  837. package/bundle/hkp-rt/lib/src/services/http_server/http_stream_listener.h +104 -0
  838. package/bundle/hkp-rt/lib/src/services/http_server/request_decode.h +164 -0
  839. package/bundle/hkp-rt/lib/src/services/if_service.h +210 -0
  840. package/bundle/hkp-rt/lib/src/services/ifft_service.h +198 -0
  841. package/bundle/hkp-rt/lib/src/services/injector.h +162 -0
  842. package/bundle/hkp-rt/lib/src/services/iterator.h +201 -0
  843. package/bundle/hkp-rt/lib/src/services/map.h +641 -0
  844. package/bundle/hkp-rt/lib/src/services/monitor.h +161 -0
  845. package/bundle/hkp-rt/lib/src/services/mp3_frames.h +119 -0
  846. package/bundle/hkp-rt/lib/src/services/mp4_to_wav.cpp +281 -0
  847. package/bundle/hkp-rt/lib/src/services/mp4_to_wav.h +263 -0
  848. package/bundle/hkp-rt/lib/src/services/peer_server/peer_registry.cpp +88 -0
  849. package/bundle/hkp-rt/lib/src/services/peer_server/peer_registry.h +43 -0
  850. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server.h +163 -0
  851. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_listener.cpp +133 -0
  852. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_listener.h +46 -0
  853. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_session.cpp +165 -0
  854. package/bundle/hkp-rt/lib/src/services/peer_server/peer_server_session.h +44 -0
  855. package/bundle/hkp-rt/lib/src/services/peer_server/peer_ws_session.cpp +184 -0
  856. package/bundle/hkp-rt/lib/src/services/peer_server/peer_ws_session.h +55 -0
  857. package/bundle/hkp-rt/lib/src/services/receiver_session.h +172 -0
  858. package/bundle/hkp-rt/lib/src/services/root_certificates.h +3959 -0
  859. package/bundle/hkp-rt/lib/src/services/sha256_openssl.h +49 -0
  860. package/bundle/hkp-rt/lib/src/services/speech_http.h +306 -0
  861. package/bundle/hkp-rt/lib/src/services/speech_to_text.cpp +595 -0
  862. package/bundle/hkp-rt/lib/src/services/speech_to_text.h +69 -0
  863. package/bundle/hkp-rt/lib/src/services/static.cpp +45 -0
  864. package/bundle/hkp-rt/lib/src/services/static.h +41 -0
  865. package/bundle/hkp-rt/lib/src/services/stopper.h +72 -0
  866. package/bundle/hkp-rt/lib/src/services/sub_service.h +286 -0
  867. package/bundle/hkp-rt/lib/src/services/text_generation.cpp +1132 -0
  868. package/bundle/hkp-rt/lib/src/services/text_generation.h +71 -0
  869. package/bundle/hkp-rt/lib/src/services/text_to_speech.cpp +853 -0
  870. package/bundle/hkp-rt/lib/src/services/text_to_speech.h +97 -0
  871. package/bundle/hkp-rt/lib/src/services/timer.h +300 -0
  872. package/bundle/hkp-rt/lib/src/services/tracks.h +397 -0
  873. package/bundle/hkp-rt/lib/src/services/tts_inflect.cpp +149 -0
  874. package/bundle/hkp-rt/lib/src/services/tts_inflect.h +82 -0
  875. package/bundle/hkp-rt/lib/src/services/wav_reader.h +213 -0
  876. package/bundle/hkp-rt/lib/src/services/websocket_client_service.h +182 -0
  877. package/bundle/hkp-rt/lib/src/services/websocket_reader.h +148 -0
  878. package/bundle/hkp-rt/lib/src/services/websocket_server_service.h +196 -0
  879. package/bundle/hkp-rt/lib/src/services/websocket_writer.cpp +641 -0
  880. package/bundle/hkp-rt/lib/src/services/websocket_writer.h +117 -0
  881. package/bundle/hkp-rt/lib/src/sub_runtime.cpp +234 -0
  882. package/bundle/hkp-rt/lib/src/sub_runtime.h +160 -0
  883. package/bundle/hkp-rt/lib/src/types/data.cpp +237 -0
  884. package/bundle/hkp-rt/lib/src/types/message.cpp +148 -0
  885. package/bundle/hkp-rt/lib/src/types/models.cpp +83 -0
  886. package/bundle/hkp-rt/lib/src/types/ringbuffer.cpp +336 -0
  887. package/bundle/hkp-rt/lib/src/uuid.h +12 -0
  888. package/bundle/readymade-mcp-commits.json +5 -0
  889. package/dist/cli.d.ts +3 -0
  890. package/dist/cli.d.ts.map +1 -0
  891. package/dist/cli.js +79 -0
  892. package/dist/git.d.ts +8 -0
  893. package/dist/git.d.ts.map +1 -0
  894. package/dist/git.js +53 -0
  895. package/dist/http.d.ts +17 -0
  896. package/dist/http.d.ts.map +1 -0
  897. package/dist/http.js +130 -0
  898. package/dist/index.d.ts +7 -0
  899. package/dist/index.d.ts.map +1 -0
  900. package/dist/index.js +6 -0
  901. package/dist/repository.d.ts +49 -0
  902. package/dist/repository.d.ts.map +1 -0
  903. package/dist/repository.js +452 -0
  904. package/dist/schemas.d.ts +156 -0
  905. package/dist/schemas.d.ts.map +1 -0
  906. package/dist/schemas.js +43 -0
  907. package/dist/server.d.ts +4 -0
  908. package/dist/server.d.ts.map +1 -0
  909. package/dist/server.js +83 -0
  910. package/dist/types.d.ts +63 -0
  911. package/dist/types.d.ts.map +1 -0
  912. package/dist/types.js +20 -0
  913. package/dist/validation.d.ts +9 -0
  914. package/dist/validation.d.ts.map +1 -0
  915. package/dist/validation.js +101 -0
  916. package/package.json +52 -4
@@ -0,0 +1,1131 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import threading
5
+
6
+ import time
7
+ import uuid as _uuid
8
+ from contextlib import contextmanager
9
+ from datetime import datetime, timezone
10
+ from typing import Any, Coroutine, Callable, Iterator, Literal
11
+
12
+ from .address import ADDRESS_SEPARATOR, descend, split_address
13
+ from .data import ControlFlowData
14
+ from .mounts import MountHandle, MountHandler, RuntimeMounts
15
+ from .secrets import SecretEntry, SecretVault
16
+ from .assets import AssetStore
17
+ from .auth import ANONYMOUS_SUB, AuthenticatedUser
18
+ from .types import (
19
+ Caller,
20
+ PersonRunActor,
21
+ RunActor,
22
+ SourceRunActor,
23
+ LogEntry,
24
+ LogLevel,
25
+ ProcessContext,
26
+ HostedService,
27
+ JsonRecord,
28
+ NotificationCallback,
29
+ RuntimeConfiguration,
30
+ RuntimeDescriptor,
31
+ RuntimeNotification,
32
+ ServiceConfiguration,
33
+ ServiceCreator,
34
+ ServiceDescriptor,
35
+ ServiceRegistryEntry,
36
+ SlotStore,
37
+ )
38
+
39
+
40
+ #: Severity order, so a runtime can drop anything below what it records.
41
+ LOG_LEVELS = {"debug": 0, "info": 1, "warn": 2, "error": 3}
42
+ DEFAULT_PERSON_RUN_TTL_MS = 15 * 60 * 1000
43
+
44
+
45
+ def iso_timestamp() -> str:
46
+ """UTC, ISO 8601, to milliseconds — what every runtime stamps an entry with.
47
+
48
+ Not ``datetime.isoformat()``, which writes microseconds and ``+00:00``. A
49
+ board's log holds entries from every runtime it spans in one file, and it is
50
+ ordered and filtered by comparing this field as text — so a stamp that spells
51
+ the same instant differently to hkp-node's and hkp-rt's sorts against them
52
+ rather than among them.
53
+ """
54
+ now = datetime.now(timezone.utc)
55
+ return f"{now.strftime('%Y-%m-%dT%H:%M:%S')}.{now.microsecond // 1000:03d}Z"
56
+
57
+
58
+ def new_run(
59
+ kind: Literal["board", "mount", "local"] = "board",
60
+ ) -> ProcessContext:
61
+ """A run with no parent: something outside the board asked for this."""
62
+ return ProcessContext(run_id=str(_uuid.uuid4()), actor=SourceRunActor(kind=kind))
63
+
64
+
65
+ def context_from_wire(value: Any) -> ProcessContext | None:
66
+ """Read a context a peer sent, filling in what it left out.
67
+
68
+ A caller that names no run is not continuing one, so a run is begun rather
69
+ than left unidentified — work that cannot be attributed to anything is worse
70
+ than work attributed to a run of its own. Returns None only when there was
71
+ no context at all, which lets the caller decide.
72
+ """
73
+ if not isinstance(value, dict):
74
+ return None
75
+
76
+ def text(key: str) -> str | None:
77
+ found = value.get(key)
78
+ return found if isinstance(found, str) and found else None
79
+
80
+ return ProcessContext(
81
+ run_id=text("runId") or str(_uuid.uuid4()),
82
+ actor=SourceRunActor(kind="local"),
83
+ parent_run_id=text("parentRunId"),
84
+ request_id=text("requestId"),
85
+ )
86
+
87
+
88
+ def caller_of(user: AuthenticatedUser | None) -> Caller | None:
89
+ """Who a signed-in user is to a run they begin, or nothing where there is
90
+ no identity to state.
91
+
92
+ A server running without authentication resolves everybody to the one
93
+ anonymous tenant. That is *no caller*, not a caller called anonymous —
94
+ otherwise everybody on a development machine would be the same person.
95
+ """
96
+ if user is None or user.sub == ANONYMOUS_SUB:
97
+ return None
98
+ # A client holding a token reaches only its own tenant's runtimes, so it
99
+ # is their owner; a member arrives through a coordinator, which says so.
100
+ return Caller(sub=user.sub, email=user.email or None, role="owner")
101
+
102
+
103
+ def context_for_client(
104
+ wire: Any, user: AuthenticatedUser | None
105
+ ) -> ProcessContext:
106
+ """The context of a run a client holding a token begins: a REST process
107
+ call, or a ``processRuntime`` on a runtime's socket.
108
+
109
+ The run metadata the client sent is kept, as ``context_from_wire`` reads
110
+ it. Whatever it said about a caller is not read at all: who is calling is
111
+ what the server verified, so a client cannot act in another person's name
112
+ by saying so.
113
+ """
114
+ context = context_from_wire(wire) or new_run("local")
115
+ caller = caller_of(user)
116
+ context.actor = (
117
+ PersonRunActor(
118
+ kind="person",
119
+ sub=caller.sub,
120
+ email=caller.email,
121
+ name=caller.name,
122
+ role=caller.role,
123
+ expires_at=int(time.time() * 1000) + DEFAULT_PERSON_RUN_TTL_MS,
124
+ )
125
+ if caller is not None
126
+ else SourceRunActor(kind="local")
127
+ )
128
+ return context
129
+
130
+
131
+ def caller_from_wire(value: Any) -> Caller | None:
132
+ """A caller as a participant link states one, or nothing when the shape
133
+ is off."""
134
+ if not isinstance(value, dict):
135
+ return None
136
+ sub = value.get("sub")
137
+ if not isinstance(sub, str) or not sub:
138
+ return None
139
+ email = value.get("email")
140
+ name = value.get("name")
141
+ role = value.get("role")
142
+ return Caller(
143
+ sub=sub,
144
+ email=email if isinstance(email, str) and email else None,
145
+ name=name if isinstance(name, str) and name else None,
146
+ role=role if role in ("owner", "member") else None,
147
+ )
148
+
149
+
150
+ def actor_from_wire(value: Any) -> RunActor | None:
151
+ """An actor as a trusted participant link states it."""
152
+ if not isinstance(value, dict):
153
+ return None
154
+ kind = value.get("kind")
155
+ if kind == "person":
156
+ caller = caller_from_wire(value)
157
+ expires_at = value.get("expiresAt")
158
+ return PersonRunActor(
159
+ kind="person",
160
+ sub=caller.sub if caller is not None else "",
161
+ email=caller.email if caller is not None else None,
162
+ name=caller.name if caller is not None else None,
163
+ role=caller.role if caller is not None else None,
164
+ expires_at=(
165
+ int(expires_at)
166
+ if isinstance(expires_at, (int, float))
167
+ and not isinstance(expires_at, bool)
168
+ else 0
169
+ ),
170
+ )
171
+ if kind in ("board", "mount", "local"):
172
+ return SourceRunActor(kind=kind)
173
+ return None
174
+
175
+
176
+ def context_from_link(value: Any) -> ProcessContext | None:
177
+ """The context of a run as a coordinator says it over a participant link.
178
+
179
+ The one path on which a caller is taken as stated. The link is the board's
180
+ own — opened by this server with the board's ticket — and the coordinator
181
+ on it is what verified the person. Kept apart from ``context_from_wire`` so
182
+ that no other entry point can come to trust a caller by sharing a parser.
183
+ """
184
+ context = context_from_wire(value)
185
+ if context is None:
186
+ return None
187
+ # The reply address belongs to whoever was waiting at the other end.
188
+ context.request_id = None
189
+ context.actor = actor_from_wire(value.get("actor")) or SourceRunActor(
190
+ kind="board"
191
+ )
192
+ return context
193
+
194
+
195
+ def context_to_wire(context: ProcessContext | None) -> dict[str, Any] | None:
196
+ """A run as it is said to another runtime: which run, and who began it.
197
+ The reply address is left out — it means something only to whoever is
198
+ waiting."""
199
+ if context is None:
200
+ return None
201
+ wire: dict[str, Any] = {"runId": context.run_id}
202
+ if context.parent_run_id:
203
+ wire["parentRunId"] = context.parent_run_id
204
+ wire["actor"] = context.actor.to_wire()
205
+ return wire
206
+
207
+
208
+ def child_run(parent: ProcessContext | None) -> ProcessContext:
209
+ """A run invoked from inside another one, as a nested pipeline is.
210
+
211
+ The child gets an identity of its own rather than borrowing its parent's, so
212
+ that work done inside a sub-pipeline stays distinguishable from work done
213
+ around it — which is the whole difference between a trace that shows nesting
214
+ and one that shows a flat list in timestamp order. The actor is inherited
215
+ exactly, whether it is a person, the board, a mount, or local work.
216
+ """
217
+ if parent is None:
218
+ return new_run()
219
+ return ProcessContext(
220
+ run_id=str(_uuid.uuid4()),
221
+ actor=parent.actor,
222
+ parent_run_id=parent.run_id,
223
+ )
224
+
225
+
226
+ def run_expired(context: ProcessContext | None, now_ms: int | None = None) -> bool:
227
+ """Person authority is invalid unless it carries a live finite deadline."""
228
+ if context is None or context.actor.kind != "person":
229
+ return False
230
+ now = int(time.time() * 1000) if now_ms is None else now_ms
231
+ return context.actor.expires_at <= now
232
+
233
+
234
+ #: The loop the server runs on, for work a service starts from a worker thread.
235
+ #:
236
+ #: A runtime's ``process`` is called on a thread pool, so a service scheduling
237
+ #: something during a pass has no running loop to schedule it on. The server
238
+ #: records its loop here once, and every runtime — nested ones included, which
239
+ #: are built during a pass and would otherwise capture nothing — schedules
240
+ #: through it.
241
+ _server_loop: asyncio.AbstractEventLoop | None = None
242
+
243
+
244
+ def set_server_loop(loop: asyncio.AbstractEventLoop | None) -> None:
245
+ """Told once by the server, at startup."""
246
+ global _server_loop
247
+ _server_loop = loop
248
+
249
+
250
+ class HostedRuntime:
251
+ def __init__(
252
+ self,
253
+ config: RuntimeConfiguration,
254
+ create_service: ServiceCreator,
255
+ mounts: RuntimeMounts | None = None,
256
+ ) -> None:
257
+ self._mounts = mounts
258
+ self.id = config.id
259
+ self.name = config.name
260
+ self.board_name = config.board_name
261
+ #: See RuntimeConfiguration.garbage_collected. False means persist.
262
+ self.garbage_collected = config.garbage_collected
263
+ self._services: dict[str, HostedService] = {}
264
+ self._service_order: list[str] = []
265
+ self._notification_targets: set[NotificationCallback] = set()
266
+ self._result_targets: set[
267
+ Callable[[Any, ProcessContext | None], None]
268
+ ] = set()
269
+ #: The call being processed right now, and which service it is inside;
270
+ #: see _context and _with_context. Kept per thread: passes run on a
271
+ #: worker thread while services are configured on the server's loop,
272
+ #: and a service may report from a thread of its own. One field shared
273
+ #: between them would let a call that began on one thread restore a
274
+ #: context saved from another, and leave a finished run in place for
275
+ #: everything that followed.
276
+ self._call = threading.local()
277
+ self._log_targets: set[Callable[[LogEntry], None]] = set()
278
+ #: Whether log entries may carry their ``data`` payload.
279
+ #:
280
+ #: Off unless a board turns it on, because ``data`` is the one free-form
281
+ #: field and therefore the only place a service can record something it
282
+ #: did not mean to. Redaction at the source is a discipline and
283
+ #: disciplines fail; leaving the channel closed by default means a lapse
284
+ #: can only escape somewhere somebody deliberately opened it.
285
+ # Absent means allowed; the per-service choice is the gate.
286
+ self._log_data = config.log_data
287
+ #: Capture mode: whether this runtime's call reports leave it with their
288
+ #: values. Switched while the board runs and never part of its
289
+ #: configuration, so a runtime always starts without it. Read where a
290
+ #: report leaves the server (``outgoing_payload``), so a pipeline nested
291
+ #: at any depth — whose reports reach the server only through this
292
+ #: runtime — follows it too.
293
+ self._capture = False
294
+ #: Whether anything is recorded at all; see RuntimeConfiguration.logging
295
+ self._logging = config.logging
296
+ self._log_level = config.log_level if config.log_level in LOG_LEVELS else "info"
297
+ self._create_service = create_service
298
+ #: Values for the references this runtime's services carry. Held apart
299
+ #: from every service's state, and reachable only through secrets().
300
+ #: Filled before any service is built, because a service that opens a
301
+ #: connection while being configured asks for its credential then.
302
+ self._vault = SecretVault()
303
+ self._vault.replace(config.secrets)
304
+ #: Where this runtime's secrets come from when they are not its own;
305
+ #: see delegate_secrets.
306
+ self._secrets_from: Callable[[], SecretVault | None] | None = None
307
+ #: The descriptors of the assets this runtime's services reference, and
308
+ #: the content they resolve to. Filled before any service is built, for
309
+ #: the same reason the vault is. Reachable through assets().
310
+ self._asset_store = AssetStore()
311
+ self._asset_store.replace(config.assets)
312
+ #: Where this runtime's assets come from when they are not its own; see
313
+ #: delegate_assets.
314
+ self._assets_from: Callable[[], AssetStore | None] | None = None
315
+ #: The cells services in this runtime hold values in between passes.
316
+ #: Owned rather than delegated by default: a runtime is the outermost
317
+ #: thing a slot name can mean, so two services that name the same slot
318
+ #: and are given nothing more specific share this one.
319
+ self._own_slots = SlotStore()
320
+ #: Where this runtime's slots come from when they are not its own;
321
+ #: see delegate_slots.
322
+ self._slots_from: Callable[[], SlotStore | None] | None = None
323
+ #: Where this runtime's mounts are claimed, when it has no server of
324
+ #: its own; see delegate_mounts.
325
+ self._mounts_from: (
326
+ Callable[[str, MountHandler, str | None], MountHandle | None] | None
327
+ ) = None
328
+
329
+ for svc_config in config.services:
330
+ self.add_service(svc_config)
331
+
332
+ # ── Serialisation ──────────────────────────────────────────────────────────
333
+
334
+ def serialize(self, output_url: str | None = None) -> RuntimeDescriptor:
335
+ return RuntimeDescriptor(
336
+ id=self.id,
337
+ name=self.name,
338
+ board_name=self.board_name,
339
+ services=self.list_services(),
340
+ inputs=[],
341
+ output_url=output_url,
342
+ )
343
+
344
+ def list_services(self) -> list[ServiceDescriptor]:
345
+ result: list[ServiceDescriptor] = []
346
+ for uuid in self._service_order:
347
+ svc = self._services.get(uuid)
348
+ if svc:
349
+ result.append(
350
+ ServiceDescriptor(
351
+ service_id=svc.service_id,
352
+ service_name=svc.service_name,
353
+ version=getattr(svc, "version", None),
354
+ capabilities=getattr(svc, "capabilities", None),
355
+ uuid=svc.uuid,
356
+ state=svc.get_state(),
357
+ )
358
+ )
359
+ return result
360
+
361
+ # ── Service management ─────────────────────────────────────────────────────
362
+
363
+ def get_service(self, address: str) -> HostedService | None:
364
+ """The service an address names, flat or scoped.
365
+
366
+ The flat list is asked first, so a uuid that happens to contain a dot
367
+ is still that service rather than a path into something else. Only when
368
+ no service carries the whole address is it read as one — see
369
+ ``address.py``.
370
+ """
371
+ direct = self._services.get(address)
372
+ if direct is not None:
373
+ return direct
374
+ segments = split_address(address)
375
+ if len(segments) < 2:
376
+ return None
377
+ head = self._services.get(segments[0])
378
+ return descend(head, segments[1:]) if head is not None else None
379
+
380
+ def add_service(self, config: ServiceConfiguration) -> JsonRecord:
381
+ if config.uuid in self._services:
382
+ raise ValueError(f"Service already exists: {config.uuid}")
383
+ svc = self._create_service(config)
384
+ if hasattr(svc, "set_host"):
385
+ svc.set_host(self)
386
+ self._services[svc.uuid] = svc
387
+ self._service_order.append(svc.uuid)
388
+ return svc.get_state()
389
+
390
+ def configure_service(
391
+ self,
392
+ address: str,
393
+ config: JsonRecord,
394
+ context: ProcessContext | None = None,
395
+ ) -> JsonRecord | None:
396
+ svc = self.get_service(address)
397
+ if not svc:
398
+ return None
399
+ if context is None:
400
+ return svc.configure(config)
401
+ with self._with_context(context):
402
+ return svc.configure(config)
403
+
404
+ def remove_service(self, uuid: str) -> bool:
405
+ svc = self._services.get(uuid)
406
+ if svc and hasattr(svc, "destroy"):
407
+ svc.destroy()
408
+ if uuid not in self._services:
409
+ return False
410
+ del self._services[uuid]
411
+ self._service_order = [u for u in self._service_order if u != uuid]
412
+ return True
413
+
414
+ def rearrange_services(self, new_order: list[str]) -> bool:
415
+ if len(new_order) != len(self._service_order):
416
+ return False
417
+ known = set(self._service_order)
418
+ for uuid in new_order:
419
+ if uuid not in known:
420
+ return False
421
+ self._service_order = list(new_order)
422
+ return True
423
+
424
+ def destroy(self) -> None:
425
+ for svc in self._services.values():
426
+ if hasattr(svc, "destroy"):
427
+ svc.destroy()
428
+ self._services.clear()
429
+ self._service_order = []
430
+ self._notification_targets.clear()
431
+ self._result_targets.clear()
432
+ self._log_targets.clear()
433
+
434
+ # ── Notification / result targets ──────────────────────────────────────────
435
+
436
+ def register_notification_target(self, target: NotificationCallback) -> Callable[[], None]:
437
+ self._notification_targets.add(target)
438
+ return lambda: self._notification_targets.discard(target)
439
+
440
+ def register_result_target(
441
+ self, target: Callable[[Any, ProcessContext | None], None]
442
+ ) -> Callable[[], None]:
443
+ """Where what this runtime emits goes. A target is told the run the
444
+ value was emitted in, or None when it was emitted outside one, so that
445
+ whoever carries it on can say which run it continues."""
446
+ self._result_targets.add(target)
447
+ return lambda: self._result_targets.discard(target)
448
+
449
+ # ── Pipeline processing ────────────────────────────────────────────────────
450
+
451
+ def process(
452
+ self,
453
+ input: Any,
454
+ on_notification: NotificationCallback,
455
+ context: ProcessContext | None = None,
456
+ ) -> Any:
457
+ with self._with_context(context or new_run()):
458
+ return self._process_from_index(0, input, on_notification)
459
+
460
+ def process_at(
461
+ self,
462
+ start_at_uuid: str,
463
+ data: Any,
464
+ on_notification: NotificationCallback,
465
+ context: ProcessContext | None = None,
466
+ ) -> Any:
467
+ """Run the pipeline starting **at** a service rather than after it.
468
+
469
+ `process_from` exists for a service handing work onward — it means
470
+ "carry on behind me", so it advances past the caller. This is the other
471
+ question: something outside the pipeline wants a particular service to
472
+ do its job with a given payload, and that service must actually run.
473
+
474
+ hkp-rt spells the same distinction as
475
+ ``processFrom(service, data, advanceBefore)``; kept as a separate entry
476
+ point here so the advancing call, which every service uses, cannot
477
+ change shape by accident.
478
+ """
479
+ try:
480
+ start_index = self._service_order.index(start_at_uuid)
481
+ except ValueError:
482
+ # Not one of this runtime's own: a scoped address enters the
483
+ # pipeline that holds it instead, and runs to the end of *that*
484
+ # list. What it produces is the nested pipeline's answer.
485
+ segments = split_address(start_at_uuid)
486
+ head = self._services.get(segments[0]) if len(segments) > 1 else None
487
+ enter = getattr(head, "process_nested", None) if head else None
488
+ if enter is None:
489
+ raise KeyError(start_at_uuid)
490
+ return enter(ADDRESS_SEPARATOR.join(segments[1:]), data, context)
491
+
492
+ # Nothing to continue: whoever asked for this is outside the board, so
493
+ # it begins a run rather than joining one.
494
+ with self._with_context(context or new_run()):
495
+ return self._process_from_index(start_index, data, on_notification)
496
+
497
+ # ── RuntimeHost interface ──────────────────────────────────────────────────
498
+
499
+ def current_context(self) -> ProcessContext | None:
500
+ return self._context
501
+
502
+ @property
503
+ def _context(self) -> ProcessContext | None:
504
+ """The call this thread is processing, or None when it is in none."""
505
+ return getattr(self._call, "context", None)
506
+
507
+ @_context.setter
508
+ def _context(self, context: ProcessContext | None) -> None:
509
+ self._call.context = context
510
+
511
+ @property
512
+ def _current_service(self) -> str | None:
513
+ """Which service this thread's pass is inside, for a log entry to name."""
514
+ return getattr(self._call, "service", None)
515
+
516
+ @_current_service.setter
517
+ def _current_service(self, uuid: str | None) -> None:
518
+ self._call.service = uuid
519
+
520
+ def process_from(
521
+ self,
522
+ start_after_uuid: str,
523
+ data: Any,
524
+ on_notification: NotificationCallback,
525
+ context: ProcessContext | None = None,
526
+ ) -> Any:
527
+ # Three ways to arrive here, and each wants a different run:
528
+ #
529
+ # - Named explicitly: a service that left its call and came back — an
530
+ # HTTP response, an awaited write — handing back what it captured.
531
+ # - Called from inside a call: a service pulling the services after it
532
+ # rather than returning to them. Still the same run, and the current
533
+ # context already says which, so nothing has to be threaded by hand.
534
+ # - Neither: a timer tick, an arriving message. Nothing to continue, so
535
+ # this begins a run.
536
+ #
537
+ # A service that leaves its call and forgets to capture lands in the
538
+ # third case, which splits its trace in two rather than attributing its
539
+ # work to whichever run happened to be in flight. Fragmentation is
540
+ # visible in a trace; misattribution reads as fact.
541
+ run_context = context or self._context or new_run()
542
+
543
+ try:
544
+ start_index = self._service_order.index(start_after_uuid) + 1
545
+ except ValueError:
546
+ start_index = len(self._service_order)
547
+
548
+ # A service pushing from itself (a Timer tick, an inbound request) was
549
+ # never called by the loop below, so the loop never reported it. Report
550
+ # it here, or the UI shows a service producing nothing while the service
551
+ # after it plainly receives data.
552
+ self._emit_notification(
553
+ RuntimeNotification(
554
+ instance_id=start_after_uuid,
555
+ payload={"__internal": {"state": "call-process", "data": None}},
556
+ ),
557
+ on_notification,
558
+ )
559
+ self._emit_notification(
560
+ RuntimeNotification(
561
+ instance_id=start_after_uuid,
562
+ payload={"__internal": {"state": "call-process-finished", "data": data}},
563
+ ),
564
+ on_notification,
565
+ )
566
+
567
+ with self._with_context(run_context):
568
+ return self._process_from_index(start_index, data, on_notification)
569
+
570
+ def mount(
571
+ self,
572
+ service_uuid: str,
573
+ handler: MountHandler,
574
+ mount_name: str | None = None,
575
+ ) -> MountHandle | None:
576
+ """Claim a publicly reachable endpoint served by the shared server.
577
+
578
+ Returns None when the host cannot serve mounts — an inner sub-service
579
+ pipeline, or a server that is not listening yet — in which case the
580
+ service has no public endpoint and should say so in its state rather
581
+ than falling back to a port of its own.
582
+
583
+ The board is named here rather than by the caller: a service knows what
584
+ its endpoint is called, and the runtime knows which board it is in, and
585
+ the address is derived from both.
586
+ """
587
+ # A nested runtime has no server of its own, so it asks the one around
588
+ # it — the same arrangement as secrets and slots. Without this an
589
+ # endpoint inside a scope had no address at all.
590
+ if self._mounts_from is not None:
591
+ return self._mounts_from(service_uuid, handler, mount_name)
592
+ if not self._mounts:
593
+ return None
594
+ return self._mounts.mount(
595
+ service_uuid,
596
+ handler,
597
+ board_name=self.board_name,
598
+ mount_name=mount_name,
599
+ )
600
+
601
+ def notify(
602
+ self,
603
+ payload: Any,
604
+ instance_id: str,
605
+ context: ProcessContext | None = None,
606
+ ) -> None:
607
+ self._emit_notification(
608
+ RuntimeNotification(
609
+ instance_id=instance_id, payload=payload, context=context
610
+ ),
611
+ lambda _: None,
612
+ )
613
+
614
+ def log(self, level: LogLevel, event: str, data: Any = None) -> None:
615
+ # Nothing to attribute an entry to means nothing worth recording: a
616
+ # service logging outside a call has no run, and an entry that names no
617
+ # run cannot be found again.
618
+ # Off means off: no entry is built, so nothing is spent deciding what
619
+ # it would have said.
620
+ if (
621
+ not self._logging
622
+ or LOG_LEVELS[level] < LOG_LEVELS[self._log_level]
623
+ or self._context is None
624
+ or not self._log_targets
625
+ ):
626
+ return
627
+
628
+ entry = LogEntry(
629
+ run_id=self._context.run_id,
630
+ parent_run_id=self._context.parent_run_id,
631
+ ts=iso_timestamp(),
632
+ runtime_id=self.id,
633
+ service_uuid=self._current_service or "",
634
+ level=level,
635
+ event=event,
636
+ data=data if (self._log_data and data is not None) else None,
637
+ caller=(
638
+ self._context.actor.sub
639
+ if self._context.actor.kind == "person"
640
+ else None
641
+ ),
642
+ )
643
+ for target in list(self._log_targets):
644
+ target(entry)
645
+
646
+ def _log_processed(self, result: Any, duration_ms: float) -> None:
647
+ """service.processed, carrying how long the call took."""
648
+ if (
649
+ not self._logging
650
+ or LOG_LEVELS["debug"] < LOG_LEVELS[self._log_level]
651
+ or self._context is None
652
+ or not self._log_targets
653
+ ):
654
+ return
655
+ entry = LogEntry(
656
+ run_id=self._context.run_id,
657
+ parent_run_id=self._context.parent_run_id,
658
+ ts=iso_timestamp(),
659
+ runtime_id=self.id,
660
+ service_uuid=self._current_service or "",
661
+ level="debug",
662
+ event="service.processed",
663
+ duration_ms=duration_ms,
664
+ caller=(
665
+ self._context.actor.sub
666
+ if self._context.actor.kind == "person"
667
+ else None
668
+ ),
669
+ )
670
+ for target in list(self._log_targets):
671
+ target(entry)
672
+
673
+ def forward_log(self, entry: LogEntry) -> None:
674
+ """Pass an entry a nested pipeline produced outward, unchanged."""
675
+ for target in list(self._log_targets):
676
+ target(entry)
677
+
678
+ def register_log_target(
679
+ self, target: Callable[[LogEntry], None]
680
+ ) -> Callable[[], None]:
681
+ """Where this runtime's entries go.
682
+
683
+ The server registers one to carry them to the board's coordinator; a
684
+ nested pipeline's host registers one to carry them out to the runtime
685
+ around it.
686
+ """
687
+ self._log_targets.add(target)
688
+ return lambda: self._log_targets.discard(target)
689
+
690
+ def set_log_data(self, enabled: bool) -> None:
691
+ self._log_data = enabled
692
+
693
+ def set_capture(self, enabled: bool) -> None:
694
+ self._capture = enabled
695
+
696
+ def captures_calls(self) -> bool:
697
+ return self._capture
698
+
699
+ def set_logging(self, enabled: bool) -> None:
700
+ self._logging = enabled
701
+
702
+ def set_log_level(self, level: str) -> None:
703
+ if level in LOG_LEVELS:
704
+ self._log_level = level
705
+
706
+ def log_settings(self) -> dict[str, bool]:
707
+ return {
708
+ "logging": self._logging,
709
+ "log_data": self._log_data,
710
+ "log_level": self._log_level,
711
+ }
712
+
713
+ def secrets(self) -> SecretVault:
714
+ """The runtime's secrets, for a service that has a credential to send.
715
+
716
+ A service holds the reference it was configured with and asks here for
717
+ the value, naming where it is about to send it. What comes back is used
718
+ and dropped: assigning it to state would put it back on the path a board
719
+ is saved from, which is the whole thing this arrangement exists to
720
+ prevent.
721
+ """
722
+ if self._secrets_from is not None:
723
+ delegated = self._secrets_from()
724
+ if delegated is not None:
725
+ return delegated
726
+ return self._vault
727
+
728
+ def set_secrets(self, entries: dict[str, SecretEntry]) -> None:
729
+ """Takes in values for references this runtime's services already hold.
730
+
731
+ Merges rather than replaces, because this is what a client editing one
732
+ entry sends, and what a client re-pushes after a restart. Replacing on a
733
+ partial push would strip credentials from services nobody touched.
734
+ """
735
+ self._vault.merge(entries)
736
+
737
+ def delegate_secrets(
738
+ self, source: Callable[[], SecretVault | None]
739
+ ) -> None:
740
+ """Take secrets from somewhere else rather than from this runtime's own.
741
+
742
+ A nested pipeline is a runtime nobody provisions: no create payload
743
+ reaches it, so its own vault stays empty and a service inside it could
744
+ never resolve a reference. What it does have is the runtime around it,
745
+ which was provisioned — so it asks that one instead.
746
+
747
+ Asked for each time rather than copied, so that a value pushed after a
748
+ board is running reaches a nested service as immediately as a top-level
749
+ one, and so that nesting composes: each level delegates outward until it
750
+ reaches the runtime that was actually given something.
751
+ """
752
+ self._secrets_from = source
753
+
754
+ def assets(self) -> AssetStore:
755
+ """The runtime's assets, for a service that consumes content by reference.
756
+
757
+ A service holds ``hkp-asset://<id>`` and resolves it here at the moment
758
+ it uses it, so an asset edited while the board runs is what the next use
759
+ gets. The content is used and dropped, never put into state.
760
+ """
761
+ if self._assets_from is not None:
762
+ delegated = self._assets_from()
763
+ if delegated is not None:
764
+ return delegated
765
+ return self._asset_store
766
+
767
+ def set_assets(self, entries: dict[str, Any]) -> None:
768
+ """Takes in descriptors, or ``None`` for an asset that was deleted.
769
+
770
+ Merges, like secrets, because a client edits one asset at a time.
771
+ """
772
+ self._asset_store.merge(entries)
773
+
774
+ def delegate_assets(self, source: Callable[[], AssetStore | None]) -> None:
775
+ """Take assets from somewhere else rather than from this runtime's own.
776
+
777
+ The same arrangement as secrets: a nested pipeline is provisioned by
778
+ nobody, so it asks the runtime around it — on each lookup, so an asset
779
+ edited while the board runs is what a nested service resolves next.
780
+ """
781
+ self._assets_from = source
782
+
783
+ def slots(self) -> SlotStore:
784
+ if self._slots_from is not None:
785
+ delegated = self._slots_from()
786
+ if delegated is not None:
787
+ return delegated
788
+ return self._own_slots
789
+
790
+ def delegate_mounts(
791
+ self,
792
+ source: Callable[[str, MountHandler, str | None], MountHandle | None],
793
+ ) -> None:
794
+ """Claim mounts somewhere else rather than on a server of this one's own.
795
+
796
+ The services here were built before this runtime could serve a mount,
797
+ so any that wanted one gave up on it; now that there is somewhere to
798
+ claim from, they are told to ask again. A service with nothing to claim
799
+ has nothing to do here and does not answer.
800
+ """
801
+ self._mounts_from = source
802
+ for svc in list(self._services.values()):
803
+ remount = getattr(svc, "remount", None)
804
+ if remount:
805
+ remount()
806
+
807
+ def delegate_slots(self, source: Callable[[], SlotStore | None]) -> None:
808
+ """Hold values somewhere other than this runtime's own cells.
809
+
810
+ What a nested pipeline shares with is decided by the service hosting
811
+ it: an endpoint that wants its two entry points to hold between them
812
+ gives both of them one store, and a service with nothing to share
813
+ passes its parent's along — so a slot named deep inside reaches the
814
+ nearest owner that declared one, and nesting never isolates what is
815
+ inside it by accident.
816
+ """
817
+ self._slots_from = source
818
+
819
+ def spawn(self, coro: Coroutine[Any, Any, Any]) -> bool:
820
+ """Run a coroutine on the server's loop, from wherever this is called.
821
+
822
+ A service that starts work during ``process`` — a request, a timer — is
823
+ running on a worker thread, where there is no loop to schedule on.
824
+ Answering False rather than raising lets a caller say so in its own
825
+ words; the coroutine is closed either way, so nothing is left
826
+ un-awaited.
827
+ """
828
+ try:
829
+ running: asyncio.AbstractEventLoop | None = asyncio.get_running_loop()
830
+ except RuntimeError:
831
+ running = None
832
+
833
+ if running is not None:
834
+ running.create_task(coro)
835
+ return True
836
+ if _server_loop is not None:
837
+ asyncio.run_coroutine_threadsafe(coro, _server_loop)
838
+ return True
839
+
840
+ coro.close()
841
+ return False
842
+
843
+ def emit_result(self, output: Any) -> None:
844
+ context = self._context
845
+ for target in list(self._result_targets):
846
+ target(output, context)
847
+
848
+ # ── Internals ──────────────────────────────────────────────────────────────
849
+
850
+ @contextmanager
851
+ def _with_context(self, context: ProcessContext) -> Iterator[None]:
852
+ """Runs the block with ``context`` current, restoring what was there.
853
+
854
+ Restoring rather than clearing is what makes this survive a service that
855
+ calls back into this runtime from inside its own ``process`` — the pull
856
+ that a cache miss or a router performs. That inner call is still part of
857
+ the outer run, and when it returns the outer loop has more services to
858
+ visit, so the context it was running under has to come back.
859
+
860
+ Safe as ambient state only because a pass is synchronous and the state
861
+ is its thread's own: it never awaits, so no second call on the thread
862
+ can interleave with this one, and a call on another thread has a
863
+ context of its own to save and restore. A pass that awaited would need
864
+ the context threaded through the call instead.
865
+ """
866
+ previous = self._context
867
+ self._context = context
868
+ try:
869
+ yield
870
+ finally:
871
+ self._context = previous
872
+
873
+ def _process_from_index(
874
+ self,
875
+ start_index: int,
876
+ input: Any,
877
+ on_notification: NotificationCallback,
878
+ ) -> Any:
879
+ result = input
880
+
881
+ for uuid in self._service_order[start_index:]:
882
+ if run_expired(self._context):
883
+ return None
884
+ svc = self._services.get(uuid)
885
+ if not svc:
886
+ continue
887
+
888
+ self._emit_notification(
889
+ RuntimeNotification(
890
+ instance_id=uuid,
891
+ payload={"__internal": {"state": "call-process", "data": result}},
892
+ ),
893
+ on_notification,
894
+ )
895
+
896
+ notification_context = self._context
897
+
898
+ def _make_notify(u: str) -> NotificationCallback:
899
+ def _notify_cb(payload: Any, inst_id: str | None = None) -> None:
900
+ self._emit_notification(
901
+ RuntimeNotification(
902
+ instance_id=inst_id or u,
903
+ payload=payload,
904
+ context=notification_context,
905
+ ),
906
+ on_notification,
907
+ )
908
+ return _notify_cb # type: ignore[return-value]
909
+
910
+ # Restored rather than cleared, for the same reason the context is:
911
+ # a service that pulls the ones after it re-enters this loop, and
912
+ # when it returns the entries that follow still belong to the
913
+ # service that pulled.
914
+ outer_service = self._current_service
915
+ self._current_service = uuid
916
+ started_at = time.monotonic()
917
+ try:
918
+ # The flow itself, at debug: which service the runtime called,
919
+ # and below, what it returned and how long it took.
920
+ #
921
+ # Deliberately without the value flowing through. The level says
922
+ # how much of the shape of a run to keep, and turning it up must
923
+ # not also start recording the data — what flows through is
924
+ # recorded only where a service was configured to record it.
925
+ self.log("debug", "service.process")
926
+ result = svc.process(result, _make_notify(uuid))
927
+ self._log_processed(result, (time.monotonic() - started_at) * 1000)
928
+ finally:
929
+ self._current_service = outer_service
930
+
931
+ # Early return: skip the remaining services, the carried result
932
+ # becomes the runtime's output.
933
+ early_return = isinstance(result, ControlFlowData)
934
+ if early_return:
935
+ result = result.result
936
+
937
+ self._emit_notification(
938
+ RuntimeNotification(
939
+ instance_id=uuid,
940
+ payload={"__internal": {"state": "call-process-finished", "data": result}},
941
+ ),
942
+ on_notification,
943
+ )
944
+
945
+ if early_return or result is None:
946
+ if result is None:
947
+ # Where the run ended, named. Above debug because it is the
948
+ # outcome of the run rather than a step in it.
949
+ self._current_service = uuid
950
+ self.log("info", "pipeline.stopped")
951
+ self._current_service = None
952
+ break
953
+
954
+ return result
955
+
956
+ def _emit_notification(
957
+ self,
958
+ notification: RuntimeNotification,
959
+ on_notification: NotificationCallback,
960
+ ) -> None:
961
+ if notification.context is None:
962
+ notification.context = self._context or new_run("board")
963
+ on_notification(notification)
964
+ for target in list(self._notification_targets):
965
+ target(notification)
966
+
967
+
968
+ # ── RuntimeApp ─────────────────────────────────────────────────────────────────
969
+
970
+
971
+ class HostedServiceFactory:
972
+ def __init__(
973
+ self,
974
+ descriptor: ServiceRegistryEntry,
975
+ create_fn: Callable[[ServiceConfiguration, ServiceCreator], HostedService],
976
+ ) -> None:
977
+ self.descriptor = descriptor
978
+ self._create_fn = create_fn
979
+
980
+ def create(self, config: ServiceConfiguration, create_service: ServiceCreator) -> HostedService:
981
+ return self._create_fn(config, create_service)
982
+
983
+
984
+ class TenantRuntimes:
985
+ """A single tenant's view of the runtime app.
986
+
987
+ Runtime ids are only unique within an owner — boards ship stable,
988
+ human-readable ids (``node``, ``chat-node``), so two users loading the same
989
+ board must each get their own runtime rather than sharing one. Every route
990
+ resolves runtimes through one of these views, so a handler cannot reach
991
+ another tenant's runtime even by id.
992
+ """
993
+
994
+ def __init__(self, owner: str, app: "RuntimeApp") -> None:
995
+ self.owner = owner
996
+ self._app = app
997
+
998
+ def create_runtime(self, config: RuntimeConfiguration) -> HostedRuntime:
999
+ return self._app.create_runtime(self.owner, config)
1000
+
1001
+ def get_runtime(self, runtime_id: str) -> HostedRuntime | None:
1002
+ return self._app.get_runtime(self.owner, runtime_id)
1003
+
1004
+ def get_runtimes(self) -> list[HostedRuntime]:
1005
+ return self._app.get_runtimes(self.owner)
1006
+
1007
+ def remove_runtime(self, runtime_id: str) -> bool:
1008
+ return self._app.remove_runtime(self.owner, runtime_id)
1009
+
1010
+ def remove_all_runtimes(self) -> None:
1011
+ self._app.remove_all_runtimes(self.owner)
1012
+
1013
+
1014
+ def board_space(owner: str, board_name: str) -> str:
1015
+ """The space the runtimes of one deployed board live in.
1016
+
1017
+ A runtime id is unique within a space, and there are two kinds. What a
1018
+ tenant's clients create over the api shares one space, named by the tenant
1019
+ alone. What a coordinator builds for a board gets a space per board, so two
1020
+ boards that both call a runtime ``python`` each keep their own, and neither
1021
+ is replaced by a client creating a runtime of that id.
1022
+
1023
+ NUL occurs in neither part, so a board's space is never a tenant's.
1024
+ """
1025
+ return f"{owner}\x00{board_name}"
1026
+
1027
+
1028
+ class RuntimeApp:
1029
+ def __init__(
1030
+ self,
1031
+ registry: dict[str, HostedServiceFactory],
1032
+ # Supplied by the server, which owns the listening socket. Absent in
1033
+ # tests and anywhere runtimes need no public endpoints.
1034
+ mounts_for: Callable[[str, str, str], RuntimeMounts] | None = None,
1035
+ ) -> None:
1036
+ self._registry = registry
1037
+ self._mounts_for = mounts_for
1038
+ # space -> runtime id -> runtime. A tenant's own space is its owner
1039
+ # key: the authenticated ``sub`` (or "anonymous" when auth is off,
1040
+ # collapsing to one bucket). A deployed board's is ``board_space``.
1041
+ self._runtimes: dict[str, dict[str, HostedRuntime]] = {}
1042
+
1043
+ def for_owner(self, owner: str) -> TenantRuntimes:
1044
+ """A tenant-scoped view; the only way route handlers reach runtimes."""
1045
+ return TenantRuntimes(owner, self)
1046
+
1047
+ def create_runtime(
1048
+ self, owner: str, config: RuntimeConfiguration, space: str | None = None
1049
+ ) -> HostedRuntime:
1050
+ """Builds a runtime for ``owner``, replacing anything under its id in
1051
+ ``space``: the tenant's own unless a board's is named."""
1052
+ space = owner if space is None else space
1053
+ owned = self._runtimes.setdefault(space, {})
1054
+ existing = owned.get(config.id)
1055
+ if existing:
1056
+ existing.destroy()
1057
+ runtime = HostedRuntime(
1058
+ config,
1059
+ self.create_service,
1060
+ self._mounts_for(owner, config.id, space) if self._mounts_for else None,
1061
+ )
1062
+ owned[runtime.id] = runtime
1063
+ return runtime
1064
+
1065
+ def get_runtime(self, space: str, runtime_id: str) -> HostedRuntime | None:
1066
+ return self._runtimes.get(space, {}).get(runtime_id)
1067
+
1068
+ def get_runtimes(self, space: str) -> list[HostedRuntime]:
1069
+ return list(self._runtimes.get(space, {}).values())
1070
+
1071
+ def get_board_runtimes(self, owner: str) -> list[HostedRuntime]:
1072
+ """The runtimes a tenant's deployed boards have here, whichever board."""
1073
+ boards = board_space(owner, "")
1074
+ return [
1075
+ runtime
1076
+ for space, owned in self._runtimes.items()
1077
+ if space.startswith(boards)
1078
+ for runtime in owned.values()
1079
+ ]
1080
+
1081
+ def count_runtimes(self, owner: str) -> int:
1082
+ """How many runtimes a tenant has, in its own space and its boards'."""
1083
+ return len(self.get_runtimes(owner)) + len(self.get_board_runtimes(owner))
1084
+
1085
+ def remove_runtime(self, space: str, runtime_id: str) -> bool:
1086
+ owned = self._runtimes.get(space)
1087
+ if not owned:
1088
+ return False
1089
+ runtime = owned.pop(runtime_id, None)
1090
+ if not owned:
1091
+ self._runtimes.pop(space, None)
1092
+ if runtime:
1093
+ runtime.destroy()
1094
+ return True
1095
+ return False
1096
+
1097
+ def remove_all_runtimes(self, owner: str) -> None:
1098
+ """Removes what is in a tenant's own space; a board's runtimes are its
1099
+ coordinator's to remove."""
1100
+ owned = self._runtimes.pop(owner, None)
1101
+ if not owned:
1102
+ return
1103
+ for runtime in owned.values():
1104
+ runtime.destroy()
1105
+
1106
+ def get_registry(self) -> list[dict[str, Any]]:
1107
+ result = []
1108
+ # A service may be registered under more than one id (an alias kept so
1109
+ # older boards still load). The registry advertises each one once, under
1110
+ # the id its descriptor calls canonical.
1111
+ seen: set[str] = set()
1112
+ for factory in self._registry.values():
1113
+ if factory.descriptor.service_id in seen:
1114
+ continue
1115
+ seen.add(factory.descriptor.service_id)
1116
+ entry: dict[str, Any] = {
1117
+ "serviceId": factory.descriptor.service_id,
1118
+ "serviceName": factory.descriptor.service_name,
1119
+ }
1120
+ if factory.descriptor.version is not None:
1121
+ entry["version"] = factory.descriptor.version
1122
+ if factory.descriptor.capabilities is not None:
1123
+ entry["capabilities"] = factory.descriptor.capabilities
1124
+ result.append(entry)
1125
+ return result
1126
+
1127
+ def create_service(self, config: ServiceConfiguration) -> HostedService:
1128
+ factory = self._registry.get(config.service_id)
1129
+ if not factory:
1130
+ raise ValueError(f"Unknown serviceId: {config.service_id}")
1131
+ return factory.create(config, self.create_service)