@sirenodeck/sirenodeck 0.1.1-alpha.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 (485) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/bin/_wrapper-shared.js +42 -0
  4. package/bin/dev.js +95 -0
  5. package/bin/sirenodeck.js +42 -0
  6. package/config/default-config.yml +117 -0
  7. package/config/starter-config.yml +54 -0
  8. package/dist/main.mjs +64702 -0
  9. package/package.json +140 -0
  10. package/src/action/executor.ts +156 -0
  11. package/src/action/index.ts +7 -0
  12. package/src/addon/api-types.ts +15 -0
  13. package/src/addon/api.ts +461 -0
  14. package/src/addon/check-runner.ts +84 -0
  15. package/src/addon/index.ts +5 -0
  16. package/src/addon/loader.ts +441 -0
  17. package/src/addon/registry.ts +230 -0
  18. package/src/addon/spec.ts +69 -0
  19. package/src/api/addon.ts +33 -0
  20. package/src/api/asset-url.ts +24 -0
  21. package/src/api/index.ts +50 -0
  22. package/src/api/protocol-internal.ts +656 -0
  23. package/src/api/protocol.ts +2 -0
  24. package/src/api/react/index.ts +11 -0
  25. package/src/api/react/registry.ts +91 -0
  26. package/src/api/react/use-addon-channel.ts +26 -0
  27. package/src/api/react/use-button-state.tsx +23 -0
  28. package/src/api/react/use-deck.ts +24 -0
  29. package/src/assets/logo.png +0 -0
  30. package/src/assets/logo72x72.png +0 -0
  31. package/src/assets/logoFull.png +0 -0
  32. package/src/builtin-addons/brightness/README.md +51 -0
  33. package/src/builtin-addons/brightness/buttons/brightness/backend.ts +13 -0
  34. package/src/builtin-addons/brightness/buttons/brightness/config.ts +10 -0
  35. package/src/builtin-addons/brightness/buttons/brightness/frontend.tsx +50 -0
  36. package/src/builtin-addons/brightness/domain/macos.ts +46 -0
  37. package/src/builtin-addons/brightness/index.d.ts +5 -0
  38. package/src/builtin-addons/brightness/index.ts +20 -0
  39. package/src/builtin-addons/brightness/poller.ts +27 -0
  40. package/src/builtin-addons/brightness/providers/darwin.ts +107 -0
  41. package/src/builtin-addons/brightness/providers/index.ts +81 -0
  42. package/src/builtin-addons/brightness/providers/linux.ts +108 -0
  43. package/src/builtin-addons/brightness/providers/windows.ts +77 -0
  44. package/src/builtin-addons/brightness/sirenodeck.json +6 -0
  45. package/src/builtin-addons/coding-agents/assets/claude-code.svg +1 -0
  46. package/src/builtin-addons/coding-agents/assets/opencode-dark-square.svg +1 -0
  47. package/src/builtin-addons/coding-agents/buttons/agent/backend.ts +82 -0
  48. package/src/builtin-addons/coding-agents/buttons/agent/config.ts +13 -0
  49. package/src/builtin-addons/coding-agents/buttons/agent/frontend.tsx +130 -0
  50. package/src/builtin-addons/coding-agents/buttons/agent/pages.tsx +150 -0
  51. package/src/builtin-addons/coding-agents/buttons/summary/backend.ts +48 -0
  52. package/src/builtin-addons/coding-agents/buttons/summary/config.ts +11 -0
  53. package/src/builtin-addons/coding-agents/buttons/summary/frontend.tsx +254 -0
  54. package/src/builtin-addons/coding-agents/decks/agents.ts +69 -0
  55. package/src/builtin-addons/coding-agents/global/backend.ts +402 -0
  56. package/src/builtin-addons/coding-agents/global-entry.ts +7 -0
  57. package/src/builtin-addons/coding-agents/hook/script.ts +123 -0
  58. package/src/builtin-addons/coding-agents/index.ts +15 -0
  59. package/src/builtin-addons/coding-agents/manifest.ts +115 -0
  60. package/src/builtin-addons/coding-agents/providers/claude-code.ts +470 -0
  61. package/src/builtin-addons/coding-agents/providers/claude-instances.ts +184 -0
  62. package/src/builtin-addons/coding-agents/providers/opencode-instances.ts +108 -0
  63. package/src/builtin-addons/coding-agents/providers/opencode.ts +636 -0
  64. package/src/builtin-addons/coding-agents/providers/registry.ts +120 -0
  65. package/src/builtin-addons/coding-agents/providers/spawn.ts +112 -0
  66. package/src/builtin-addons/coding-agents/shared/claude-hook-events.ts +55 -0
  67. package/src/builtin-addons/coding-agents/shared/claude-status.ts +236 -0
  68. package/src/builtin-addons/coding-agents/shared/live-count.ts +39 -0
  69. package/src/builtin-addons/coding-agents/shared/notifier.ts +58 -0
  70. package/src/builtin-addons/coding-agents/shared/opencode-status.ts +82 -0
  71. package/src/builtin-addons/coding-agents/shared/snapshot.ts +66 -0
  72. package/src/builtin-addons/coding-agents/shared/state.ts +72 -0
  73. package/src/builtin-addons/coding-agents/sirenodeck.json +6 -0
  74. package/src/builtin-addons/coding-agents/types/types.ts +33 -0
  75. package/src/builtin-addons/core/README.md +89 -0
  76. package/src/builtin-addons/core/buttons/action/backend.ts +7 -0
  77. package/src/builtin-addons/core/buttons/action/config.ts +13 -0
  78. package/src/builtin-addons/core/buttons/action/frontend.tsx +16 -0
  79. package/src/builtin-addons/core/buttons/change-deck/backend.ts +18 -0
  80. package/src/builtin-addons/core/buttons/change-deck/config.ts +15 -0
  81. package/src/builtin-addons/core/buttons/change-deck/frontend.tsx +18 -0
  82. package/src/builtin-addons/core/buttons/media-sample/backend.ts +8 -0
  83. package/src/builtin-addons/core/buttons/media-sample/config.ts +7 -0
  84. package/src/builtin-addons/core/buttons/media-sample/frontend.tsx +2 -0
  85. package/src/builtin-addons/core/buttons/page-nav/backend.ts +28 -0
  86. package/src/builtin-addons/core/buttons/page-nav/config.ts +9 -0
  87. package/src/builtin-addons/core/buttons/page-nav/frontend.tsx +68 -0
  88. package/src/builtin-addons/core/buttons/toggle/backend.ts +119 -0
  89. package/src/builtin-addons/core/buttons/toggle/config.ts +57 -0
  90. package/src/builtin-addons/core/buttons/toggle/frontend.tsx +57 -0
  91. package/src/builtin-addons/core/buttons/toggle/global-service.ts +174 -0
  92. package/src/builtin-addons/core/index.ts +120 -0
  93. package/src/builtin-addons/core/sirenodeck.json +6 -0
  94. package/src/builtin-addons/date-time/README.md +73 -0
  95. package/src/builtin-addons/date-time/buttons/analog-clock/backend.ts +10 -0
  96. package/src/builtin-addons/date-time/buttons/analog-clock/config.ts +4 -0
  97. package/src/builtin-addons/date-time/buttons/analog-clock/frontend.tsx +88 -0
  98. package/src/builtin-addons/date-time/buttons/custom/backend.ts +10 -0
  99. package/src/builtin-addons/date-time/buttons/custom/config.ts +9 -0
  100. package/src/builtin-addons/date-time/buttons/custom/frontend.tsx +26 -0
  101. package/src/builtin-addons/date-time/buttons/date/backend.ts +10 -0
  102. package/src/builtin-addons/date-time/buttons/date/config.ts +10 -0
  103. package/src/builtin-addons/date-time/buttons/date/frontend.tsx +42 -0
  104. package/src/builtin-addons/date-time/buttons/time/backend.ts +10 -0
  105. package/src/builtin-addons/date-time/buttons/time/config.ts +9 -0
  106. package/src/builtin-addons/date-time/buttons/time/frontend.tsx +29 -0
  107. package/src/builtin-addons/date-time/index.d.ts +5 -0
  108. package/src/builtin-addons/date-time/index.ts +30 -0
  109. package/src/builtin-addons/date-time/poller.ts +11 -0
  110. package/src/builtin-addons/date-time/shared/format-date.ts +36 -0
  111. package/src/builtin-addons/date-time/shared/format.ts +105 -0
  112. package/src/builtin-addons/date-time/shared/use-now.ts +10 -0
  113. package/src/builtin-addons/date-time/sirenodeck.json +6 -0
  114. package/src/builtin-addons/emoji-selector/README.md +45 -0
  115. package/src/builtin-addons/emoji-selector/assets/launcher.svg +10 -0
  116. package/src/builtin-addons/emoji-selector/assets/smileys.svg +8 -0
  117. package/src/builtin-addons/emoji-selector/buttons/category/backend.ts +14 -0
  118. package/src/builtin-addons/emoji-selector/buttons/category/config.ts +8 -0
  119. package/src/builtin-addons/emoji-selector/buttons/category/frontend.tsx +19 -0
  120. package/src/builtin-addons/emoji-selector/buttons/emoji/backend.ts +7 -0
  121. package/src/builtin-addons/emoji-selector/buttons/emoji/config.ts +9 -0
  122. package/src/builtin-addons/emoji-selector/buttons/emoji/frontend.tsx +11 -0
  123. package/src/builtin-addons/emoji-selector/buttons/launcher/backend.ts +13 -0
  124. package/src/builtin-addons/emoji-selector/buttons/launcher/config.ts +6 -0
  125. package/src/builtin-addons/emoji-selector/buttons/launcher/frontend.tsx +31 -0
  126. package/src/builtin-addons/emoji-selector/data/categories.ts +1084 -0
  127. package/src/builtin-addons/emoji-selector/decks/index.ts +137 -0
  128. package/src/builtin-addons/emoji-selector/index.d.ts +5 -0
  129. package/src/builtin-addons/emoji-selector/index.ts +29 -0
  130. package/src/builtin-addons/emoji-selector/sirenodeck.json +6 -0
  131. package/src/builtin-addons/emoji-selector/support.ts +49 -0
  132. package/src/builtin-addons/index.ts +13 -0
  133. package/src/builtin-addons/internal-settings/README.md +26 -0
  134. package/src/builtin-addons/internal-settings/backend.ts +58 -0
  135. package/src/builtin-addons/internal-settings/buttons/app-info/backend.ts +7 -0
  136. package/src/builtin-addons/internal-settings/buttons/app-info/config.ts +13 -0
  137. package/src/builtin-addons/internal-settings/buttons/app-info/frontend.tsx +18 -0
  138. package/src/builtin-addons/internal-settings/buttons/brightness/common/frontend.tsx +50 -0
  139. package/src/builtin-addons/internal-settings/buttons/brightness-down/backend.ts +16 -0
  140. package/src/builtin-addons/internal-settings/buttons/brightness-down/config.ts +6 -0
  141. package/src/builtin-addons/internal-settings/buttons/brightness-down/frontend.tsx +8 -0
  142. package/src/builtin-addons/internal-settings/buttons/brightness-up/backend.ts +16 -0
  143. package/src/builtin-addons/internal-settings/buttons/brightness-up/config.ts +6 -0
  144. package/src/builtin-addons/internal-settings/buttons/brightness-up/frontend.tsx +8 -0
  145. package/src/builtin-addons/internal-settings/decks/settings.ts +25 -0
  146. package/src/builtin-addons/internal-settings/index.d.ts +4 -0
  147. package/src/builtin-addons/internal-settings/index.ts +53 -0
  148. package/src/builtin-addons/internal-settings/logo72x72.png +0 -0
  149. package/src/builtin-addons/internal-settings/sirenodeck.json +6 -0
  150. package/src/builtin-addons/media/README.md +45 -0
  151. package/src/builtin-addons/media/backend.ts +143 -0
  152. package/src/builtin-addons/media/buttons/media-player/backend.ts +19 -0
  153. package/src/builtin-addons/media/buttons/media-player/components/MediaStatus.tsx +25 -0
  154. package/src/builtin-addons/media/buttons/media-player/components/MediaSurface.tsx +52 -0
  155. package/src/builtin-addons/media/buttons/media-player/components/ProgressBar.tsx +21 -0
  156. package/src/builtin-addons/media/buttons/media-player/components/status-meta.ts +36 -0
  157. package/src/builtin-addons/media/buttons/media-player/config.ts +4 -0
  158. package/src/builtin-addons/media/buttons/media-player/frontend.tsx +29 -0
  159. package/src/builtin-addons/media/buttons/volume/common/frontend.tsx +52 -0
  160. package/src/builtin-addons/media/buttons/volume/mute/backend.ts +13 -0
  161. package/src/builtin-addons/media/buttons/volume/mute/config.ts +4 -0
  162. package/src/builtin-addons/media/buttons/volume/mute/frontend.tsx +26 -0
  163. package/src/builtin-addons/media/buttons/volume/volume-down/backend.ts +14 -0
  164. package/src/builtin-addons/media/buttons/volume/volume-down/config.ts +6 -0
  165. package/src/builtin-addons/media/buttons/volume/volume-down/frontend.tsx +10 -0
  166. package/src/builtin-addons/media/buttons/volume/volume-up/backend.ts +14 -0
  167. package/src/builtin-addons/media/buttons/volume/volume-up/config.ts +6 -0
  168. package/src/builtin-addons/media/buttons/volume/volume-up/frontend.tsx +8 -0
  169. package/src/builtin-addons/media/checks.ts +104 -0
  170. package/src/builtin-addons/media/executor.ts +36 -0
  171. package/src/builtin-addons/media/index.d.ts +5 -0
  172. package/src/builtin-addons/media/index.ts +53 -0
  173. package/src/builtin-addons/media/progress.ts +16 -0
  174. package/src/builtin-addons/media/providers/darwin.ts +391 -0
  175. package/src/builtin-addons/media/providers/index.ts +27 -0
  176. package/src/builtin-addons/media/providers/linux.ts +196 -0
  177. package/src/builtin-addons/media/providers/types.ts +48 -0
  178. package/src/builtin-addons/media/providers/windows.ts +121 -0
  179. package/src/builtin-addons/media/sirenodeck.json +6 -0
  180. package/src/builtin-addons/media/state.ts +19 -0
  181. package/src/builtin-addons/register-builtins.ts +65 -0
  182. package/src/builtin-addons/session/README.md +14 -0
  183. package/src/builtin-addons/session/buttons/session-info/backend.ts +8 -0
  184. package/src/builtin-addons/session/buttons/session-info/config.ts +4 -0
  185. package/src/builtin-addons/session/buttons/session-info/frontend.tsx +2 -0
  186. package/src/builtin-addons/session/buttons/time/backend.ts +7 -0
  187. package/src/builtin-addons/session/buttons/time/config.ts +6 -0
  188. package/src/builtin-addons/session/buttons/time/frontend.tsx +2 -0
  189. package/src/builtin-addons/session/index.d.ts +5 -0
  190. package/src/builtin-addons/session/index.ts +18 -0
  191. package/src/builtin-addons/session/sirenodeck.json +6 -0
  192. package/src/builtin-addons/system-status/README.md +169 -0
  193. package/src/builtin-addons/system-status/buttons/_shared.ts +131 -0
  194. package/src/builtin-addons/system-status/buttons/system-status/frontend.tsx +224 -0
  195. package/src/builtin-addons/system-status/buttons/system-status/schemas.ts +67 -0
  196. package/src/builtin-addons/system-status/domain/catalog.ts +53 -0
  197. package/src/builtin-addons/system-status/domain/chart-sampler.ts +58 -0
  198. package/src/builtin-addons/system-status/domain/display-metrics.ts +128 -0
  199. package/src/builtin-addons/system-status/domain/index.ts +10 -0
  200. package/src/builtin-addons/system-status/domain/live-metrics.ts +1021 -0
  201. package/src/builtin-addons/system-status/domain/metric-ids.ts +0 -0
  202. package/src/builtin-addons/system-status/index.ts +16 -0
  203. package/src/builtin-addons/system-status/manifest.ts +105 -0
  204. package/src/builtin-addons/system-status/shared/metrics-catalog.ts +316 -0
  205. package/src/builtin-addons/system-status/sirenodeck.json +6 -0
  206. package/src/builtin-addons/test-buildin/decks/action-buttons-test.ts +56 -0
  207. package/src/builtin-addons/test-buildin/index.d.ts +5 -0
  208. package/src/builtin-addons/test-buildin/index.ts +16 -0
  209. package/src/builtin-addons/value-display/README.md +59 -0
  210. package/src/builtin-addons/value-display/backend.ts +86 -0
  211. package/src/builtin-addons/value-display/buttons/value-display/backend.ts +17 -0
  212. package/src/builtin-addons/value-display/buttons/value-display/config.ts +36 -0
  213. package/src/builtin-addons/value-display/buttons/value-display/frontend.tsx +54 -0
  214. package/src/builtin-addons/value-display/index.d.ts +5 -0
  215. package/src/builtin-addons/value-display/index.ts +23 -0
  216. package/src/builtin-addons/value-display/sirenodeck.json +6 -0
  217. package/src/builtin-addons/weather/README.md +46 -0
  218. package/src/builtin-addons/weather/backend.ts +121 -0
  219. package/src/builtin-addons/weather/buttons/weather/backend.ts +27 -0
  220. package/src/builtin-addons/weather/buttons/weather/config.ts +29 -0
  221. package/src/builtin-addons/weather/buttons/weather/frontend.tsx +63 -0
  222. package/src/builtin-addons/weather/buttons/weather/icons.tsx +88 -0
  223. package/src/builtin-addons/weather/buttons/weather/pages.tsx +109 -0
  224. package/src/builtin-addons/weather/domain/codes.ts +35 -0
  225. package/src/builtin-addons/weather/domain/fetch.ts +47 -0
  226. package/src/builtin-addons/weather/index.d.ts +5 -0
  227. package/src/builtin-addons/weather/index.ts +23 -0
  228. package/src/builtin-addons/weather/poller.ts +70 -0
  229. package/src/builtin-addons/weather/provider/city-key.ts +9 -0
  230. package/src/builtin-addons/weather/provider/codes.ts +35 -0
  231. package/src/builtin-addons/weather/provider/fetch.ts +97 -0
  232. package/src/builtin-addons/weather/provider/geocode.ts +67 -0
  233. package/src/builtin-addons/weather/provider/types.ts +42 -0
  234. package/src/builtin-addons/weather/sirenodeck.json +6 -0
  235. package/src/cli/coding-agents-onboarding.ts +434 -0
  236. package/src/cli/commands/addon-decks.ts +441 -0
  237. package/src/cli/commands/addon-registry.ts +639 -0
  238. package/src/cli/commands/emulator-mode.ts +289 -0
  239. package/src/cli/commands/install.ts +128 -0
  240. package/src/cli/commands/logs.ts +74 -0
  241. package/src/cli/commands/network-bind.ts +111 -0
  242. package/src/cli/commands/pipeline/helpers.ts +75 -0
  243. package/src/cli/commands/pipeline/preflight.ts +20 -0
  244. package/src/cli/commands/port-identity.ts +152 -0
  245. package/src/cli/commands/reload.ts +37 -0
  246. package/src/cli/commands/restart.ts +139 -0
  247. package/src/cli/commands/run.ts +2270 -0
  248. package/src/cli/commands/service/install.ts +121 -0
  249. package/src/cli/commands/service/render-template.ts +158 -0
  250. package/src/cli/commands/service-manager.ts +184 -0
  251. package/src/cli/commands/spawn-daemon.ts +251 -0
  252. package/src/cli/commands/start.ts +1061 -0
  253. package/src/cli/commands/status.ts +110 -0
  254. package/src/cli/commands/stop.ts +121 -0
  255. package/src/cli/commands/subprocess-supervisor.ts +203 -0
  256. package/src/cli/commands/system-requirements.ts +699 -0
  257. package/src/cli/cwd.ts +28 -0
  258. package/src/cli/first-run.ts +149 -0
  259. package/src/cli/http-server.ts +244 -0
  260. package/src/cli/index.ts +355 -0
  261. package/src/cli/install-root.ts +26 -0
  262. package/src/cli/main.ts +194 -0
  263. package/src/cli/package-manager.ts +175 -0
  264. package/src/cli/probe-deps.ts +45 -0
  265. package/src/cli/prompt.ts +22 -0
  266. package/src/cli/startup-display.ts +452 -0
  267. package/src/config/builtin-icons.ts +57 -0
  268. package/src/config/config-diff.ts +54 -0
  269. package/src/config/discovery.ts +64 -0
  270. package/src/config/icon-resolver.ts +90 -0
  271. package/src/config/include-resolver.ts +202 -0
  272. package/src/config/index.ts +9 -0
  273. package/src/config/loader.ts +187 -0
  274. package/src/config/mutation.ts +514 -0
  275. package/src/config/reference-expander.ts +84 -0
  276. package/src/config/schemas.ts +223 -0
  277. package/src/config/validation.ts +254 -0
  278. package/src/core/asset-id.ts +21 -0
  279. package/src/core/gesture-state.ts +344 -0
  280. package/src/core/icon-asset-registry.ts +127 -0
  281. package/src/core/icon-source.ts +86 -0
  282. package/src/core/index.ts +30 -0
  283. package/src/core/mime.ts +16 -0
  284. package/src/core/pagination.ts +90 -0
  285. package/src/core/pub-sub.ts +126 -0
  286. package/src/core/settings.ts +153 -0
  287. package/src/core/store.ts +88 -0
  288. package/src/core/watcher.ts +73 -0
  289. package/src/deck/addon-handler-bridge.ts +516 -0
  290. package/src/deck/deck-config.ts +271 -0
  291. package/src/deck/editor-surfaces.ts +87 -0
  292. package/src/deck/host-context.ts +18 -0
  293. package/src/deck/index.ts +102 -0
  294. package/src/deck/macro-parse.ts +182 -0
  295. package/src/deck/methods.ts +348 -0
  296. package/src/deck/paginate-deck.ts +98 -0
  297. package/src/deck/position-buttons.ts +57 -0
  298. package/src/deck/runtime/index.ts +5 -0
  299. package/src/deck/runtime/runtime.ts +1060 -0
  300. package/src/deck/runtime-subscriptions.ts +45 -0
  301. package/src/deck/system-back-injection.ts +62 -0
  302. package/src/deck/system-buttons/registry.tsx +97 -0
  303. package/src/deck/system-buttons/types.ts +14 -0
  304. package/src/device/black-frame.ts +73 -0
  305. package/src/device/index.ts +13 -0
  306. package/src/device/linux-udev.ts +36 -0
  307. package/src/device/models.ts +89 -0
  308. package/src/device/reconnecting.ts +193 -0
  309. package/src/device/registry.ts +38 -0
  310. package/src/device/stream-deck.ts +155 -0
  311. package/src/index.ts +74 -0
  312. package/src/outputClient/emulator.ts +357 -0
  313. package/src/outputClient/index.ts +26 -0
  314. package/src/outputClient/open-browser.ts +26 -0
  315. package/src/outputClient/real.ts +393 -0
  316. package/src/outputClient/types.ts +83 -0
  317. package/src/render/browser-renderer.ts +240 -0
  318. package/src/render/buffer-hash.ts +20 -0
  319. package/src/render/editor-handler.ts +197 -0
  320. package/src/render/emulator-server.ts +128 -0
  321. package/src/render/icon-source-resolver.ts +69 -0
  322. package/src/render/index.ts +16 -0
  323. package/src/render/protocol.ts +61 -0
  324. package/src/render/push-raw-image.ts +100 -0
  325. package/src/render/screenshot-cadence.ts +87 -0
  326. package/src/render/state-publisher.ts +110 -0
  327. package/src/render/vite-server.ts +138 -0
  328. package/src/render/ws-bridge.ts +315 -0
  329. package/src/system/device-selection.ts +80 -0
  330. package/src/system/glob-match.ts +74 -0
  331. package/src/system/providers/active-app/darwin.ts +117 -0
  332. package/src/system/providers/active-app/linux.ts +245 -0
  333. package/src/system/providers/active-app/wayland-gnome.ts +303 -0
  334. package/src/system/providers/active-app/windows.ts +94 -0
  335. package/src/system/providers/active-app.ts +97 -0
  336. package/src/system/providers/clipboard/darwin.ts +65 -0
  337. package/src/system/providers/clipboard/linux.ts +163 -0
  338. package/src/system/providers/clipboard/windows.ts +94 -0
  339. package/src/system/providers/clipboard.ts +84 -0
  340. package/src/system/providers/error.ts +16 -0
  341. package/src/system/providers/key-macro/darwin.ts +221 -0
  342. package/src/system/providers/key-macro/linux.ts +651 -0
  343. package/src/system/providers/key-macro/parser.ts +215 -0
  344. package/src/system/providers/key-macro/windows.ts +476 -0
  345. package/src/system/providers/key-macro.ts +79 -0
  346. package/src/system/providers/notification/darwin.ts +36 -0
  347. package/src/system/providers/notification/linux.ts +115 -0
  348. package/src/system/providers/notification/windows.ts +72 -0
  349. package/src/system/providers/notification.ts +75 -0
  350. package/src/system/providers/session/darwin.ts +82 -0
  351. package/src/system/providers/session/linux.ts +175 -0
  352. package/src/system/providers/session/windows.ts +73 -0
  353. package/src/system/providers/session.ts +89 -0
  354. package/src/system/providers/shared.ts +65 -0
  355. package/src/system/requirements.ts +235 -0
  356. package/src/system/setup-wizard/config-seed.ts +30 -0
  357. package/src/system/setup-wizard/format.ts +275 -0
  358. package/src/system/setup-wizard/index.ts +45 -0
  359. package/src/system/setup-wizard/open-settings.ts +26 -0
  360. package/src/system/setup-wizard/plan.ts +230 -0
  361. package/src/system/setup-wizard/probe-cache.ts +34 -0
  362. package/src/system/setup-wizard/probe.ts +486 -0
  363. package/src/system/setup-wizard/runtime-features.ts +85 -0
  364. package/src/system/setup-wizard/sudo.ts +178 -0
  365. package/src/system/setup-wizard/types.ts +133 -0
  366. package/src/system/virtual-stream-deck.ts +67 -0
  367. package/src/themes/css.ts +210 -0
  368. package/src/themes/default/assets/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  369. package/src/themes/default/assets/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
  370. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Bold.ttf +0 -0
  371. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf +0 -0
  372. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf +0 -0
  373. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf +0 -0
  374. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Italic.ttf +0 -0
  375. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Light.ttf +0 -0
  376. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf +0 -0
  377. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Medium.ttf +0 -0
  378. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf +0 -0
  379. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Regular.ttf +0 -0
  380. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf +0 -0
  381. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf +0 -0
  382. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Thin.ttf +0 -0
  383. package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf +0 -0
  384. package/src/themes/default/assets/IBM_Plex_Mono/OFL.txt +93 -0
  385. package/src/themes/default/assets/OFL.txt +93 -0
  386. package/src/themes/default/assets/README.txt +106 -0
  387. package/src/themes/default/assets/static/IBMPlexSans-Bold.ttf +0 -0
  388. package/src/themes/default/assets/static/IBMPlexSans-BoldItalic.ttf +0 -0
  389. package/src/themes/default/assets/static/IBMPlexSans-ExtraLight.ttf +0 -0
  390. package/src/themes/default/assets/static/IBMPlexSans-ExtraLightItalic.ttf +0 -0
  391. package/src/themes/default/assets/static/IBMPlexSans-Italic.ttf +0 -0
  392. package/src/themes/default/assets/static/IBMPlexSans-Light.ttf +0 -0
  393. package/src/themes/default/assets/static/IBMPlexSans-LightItalic.ttf +0 -0
  394. package/src/themes/default/assets/static/IBMPlexSans-Medium.ttf +0 -0
  395. package/src/themes/default/assets/static/IBMPlexSans-MediumItalic.ttf +0 -0
  396. package/src/themes/default/assets/static/IBMPlexSans-Regular.ttf +0 -0
  397. package/src/themes/default/assets/static/IBMPlexSans-SemiBold.ttf +0 -0
  398. package/src/themes/default/assets/static/IBMPlexSans-SemiBoldItalic.ttf +0 -0
  399. package/src/themes/default/assets/static/IBMPlexSans-Thin.ttf +0 -0
  400. package/src/themes/default/assets/static/IBMPlexSans-ThinItalic.ttf +0 -0
  401. package/src/themes/default/assets/static/IBMPlexSans_Condensed-Bold.ttf +0 -0
  402. package/src/themes/default/assets/static/IBMPlexSans_Condensed-BoldItalic.ttf +0 -0
  403. package/src/themes/default/assets/static/IBMPlexSans_Condensed-ExtraLight.ttf +0 -0
  404. package/src/themes/default/assets/static/IBMPlexSans_Condensed-ExtraLightItalic.ttf +0 -0
  405. package/src/themes/default/assets/static/IBMPlexSans_Condensed-Italic.ttf +0 -0
  406. package/src/themes/default/assets/static/IBMPlexSans_Condensed-Light.ttf +0 -0
  407. package/src/themes/default/assets/static/IBMPlexSans_Condensed-LightItalic.ttf +0 -0
  408. package/src/themes/default/assets/static/IBMPlexSans_Condensed-Medium.ttf +0 -0
  409. package/src/themes/default/assets/static/IBMPlexSans_Condensed-MediumItalic.ttf +0 -0
  410. package/src/themes/default/assets/static/IBMPlexSans_Condensed-Regular.ttf +0 -0
  411. package/src/themes/default/assets/static/IBMPlexSans_Condensed-SemiBold.ttf +0 -0
  412. package/src/themes/default/assets/static/IBMPlexSans_Condensed-SemiBoldItalic.ttf +0 -0
  413. package/src/themes/default/assets/static/IBMPlexSans_Condensed-Thin.ttf +0 -0
  414. package/src/themes/default/assets/static/IBMPlexSans_Condensed-ThinItalic.ttf +0 -0
  415. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Bold.ttf +0 -0
  416. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-BoldItalic.ttf +0 -0
  417. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-ExtraLight.ttf +0 -0
  418. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-ExtraLightItalic.ttf +0 -0
  419. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Italic.ttf +0 -0
  420. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Light.ttf +0 -0
  421. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-LightItalic.ttf +0 -0
  422. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Medium.ttf +0 -0
  423. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-MediumItalic.ttf +0 -0
  424. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Regular.ttf +0 -0
  425. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-SemiBold.ttf +0 -0
  426. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
  427. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Thin.ttf +0 -0
  428. package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-ThinItalic.ttf +0 -0
  429. package/src/themes/default/components.css +81 -0
  430. package/src/themes/default/sirenodeck.json +170 -0
  431. package/src/themes/index.ts +14 -0
  432. package/src/themes/light/assets/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  433. package/src/themes/light/assets/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
  434. package/src/themes/light/assets/IBM_Plex_Mono/IBMPlexMono-Bold.ttf +0 -0
  435. package/src/themes/light/assets/IBM_Plex_Mono/IBMPlexMono-Medium.ttf +0 -0
  436. package/src/themes/light/assets/IBM_Plex_Mono/IBMPlexMono-Regular.ttf +0 -0
  437. package/src/themes/light/assets/IBM_Plex_Mono/OFL.txt +93 -0
  438. package/src/themes/light/assets/OFL.txt +93 -0
  439. package/src/themes/light/assets/README.txt +106 -0
  440. package/src/themes/light/assets/static/IBMPlexSans-Light.ttf +0 -0
  441. package/src/themes/light/assets/static/IBMPlexSans-LightItalic.ttf +0 -0
  442. package/src/themes/light/assets/static/IBMPlexSans-Thin.ttf +0 -0
  443. package/src/themes/light/components.css +70 -0
  444. package/src/themes/light/sirenodeck.json +170 -0
  445. package/src/themes/loader.ts +343 -0
  446. package/src/themes/manifest.ts +164 -0
  447. package/src/themes/use-resolved-theme.tsx +32 -0
  448. package/src/ui/ButtonFrame.tsx +230 -0
  449. package/src/ui/contexts/AssetCacheContext.tsx +43 -0
  450. package/src/ui/index.ts +20 -0
  451. package/src/ui/primitives/Chip.tsx +53 -0
  452. package/src/ui/primitives/Icon.tsx +209 -0
  453. package/src/ui/primitives/Label.tsx +82 -0
  454. package/src/ui/primitives/ProgressBar.tsx +38 -0
  455. package/src/ui/primitives/TapIndicator.tsx +67 -0
  456. package/src/ui/primitives/Text.tsx +810 -0
  457. package/src/ui/primitives/index.ts +6 -0
  458. package/src/ui/surfaces/BarsSurface.tsx +211 -0
  459. package/src/ui/surfaces/IconLabelProgressSurface.tsx +133 -0
  460. package/src/ui/surfaces/IconLabelSurface.tsx +59 -0
  461. package/src/ui/surfaces/LabelValueListSurface.tsx +202 -0
  462. package/src/ui/surfaces/PaginatedSurface.tsx +164 -0
  463. package/src/ui/surfaces/SplitActionSurface.tsx +98 -0
  464. package/src/ui/surfaces/TemporaryErrorSurface.tsx +68 -0
  465. package/src/ui/surfaces/ValueChart.tsx +218 -0
  466. package/src/ui/surfaces/index.ts +32 -0
  467. package/src/ui/surfaces/paginated-schema.ts +22 -0
  468. package/src/ui/theme-presentation-builder.ts +184 -0
  469. package/src/ui/theme-presentation.tsx +146 -0
  470. package/src/ui/utils/cn.ts +12 -0
  471. package/src/util/cache-paths.ts +38 -0
  472. package/src/util/config-diff.ts +16 -0
  473. package/src/util/daemon-control.ts +85 -0
  474. package/src/util/daemon.ts +575 -0
  475. package/src/util/device-config.ts +56 -0
  476. package/src/util/errors.ts +13 -0
  477. package/src/util/log-reader.ts +114 -0
  478. package/src/util/log-tail.ts +103 -0
  479. package/src/util/logger.ts +417 -0
  480. package/src/util/process-title.ts +79 -0
  481. package/src/util/single-instance.ts +202 -0
  482. package/src/version.ts +10 -0
  483. package/src/vite/index.ts +6 -0
  484. package/src/vite/virtual-modules.ts +631 -0
  485. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,57 @@
1
+ import { useAddonChannel } from "@/api/react"
2
+ import { IconLabelSurface } from "@/ui/surfaces/IconLabelSurface"
3
+ import { Text } from "@/ui/primitives/Text"
4
+ import type { AddonFrontendButton } from "@/addon/api"
5
+
6
+ import type { ConfigSchema, StatusToggleConfig } from "./config"
7
+ import { isLegacyToggleConfig, isStatusToggleConfig } from "./config"
8
+ import {
9
+ TOGGLE_STATES_CHANNEL,
10
+ type ToggleStatesPayload,
11
+ } from "./global-service"
12
+
13
+ const fallback = (label: string): React.ReactElement => (
14
+ <Text tone="muted" text={label} />
15
+ )
16
+
17
+ const ToggleButtonFrontend: AddonFrontendButton<ConfigSchema> = ({
18
+ config,
19
+ buttonId,
20
+ }) => {
21
+ if (isLegacyToggleConfig(config)) {
22
+ return fallback("—")
23
+ }
24
+ if (!isStatusToggleConfig(config)) {
25
+ return fallback("—")
26
+ }
27
+ return <StatusToggleRenderer config={config} buttonId={buttonId} />
28
+ }
29
+
30
+ function StatusToggleRenderer({
31
+ config,
32
+ buttonId,
33
+ }: {
34
+ config: StatusToggleConfig
35
+ buttonId: string
36
+ }) {
37
+ const { data } = useAddonChannel<ToggleStatesPayload>(TOGGLE_STATES_CHANNEL)
38
+ const entry = data?.byButton[buttonId] ?? undefined
39
+ if (entry === undefined || entry === null) {
40
+ return fallback("…")
41
+ }
42
+ if (entry.error !== undefined) {
43
+ return fallback("err")
44
+ }
45
+ const matched =
46
+ entry.state !== undefined ? config.states[entry.state] : undefined
47
+ if (matched !== undefined) {
48
+ const label = matched.label ?? entry.state ?? ""
49
+ return <IconLabelSurface source={matched.icon} label={label} />
50
+ }
51
+ if (entry.raw.length === 0) {
52
+ return fallback("…")
53
+ }
54
+ return fallback(entry.raw)
55
+ }
56
+
57
+ export default ToggleButtonFrontend
@@ -0,0 +1,174 @@
1
+ import type { AddonServiceContext, AddonGlobalService } from "@/addon/api"
2
+
3
+ import {
4
+ TOGGLE_DEFAULT_INTERVAL_MS,
5
+ TOGGLE_DEFAULT_TIMEOUT_MS,
6
+ type StatusToggleConfig,
7
+ } from "./config"
8
+
9
+ export const TOGGLE_STATES_CHANNEL = "core:toggle:states"
10
+ export const TOGGLE_POLL_TICK_MS = 1000
11
+
12
+ export interface ToggleState {
13
+ readonly raw: string
14
+ readonly state: string | undefined
15
+ readonly error?: string
16
+ readonly at: number
17
+ }
18
+
19
+ export interface ToggleStatesPayload {
20
+ readonly byButton: Readonly<Record<string, ToggleState | null>>
21
+ }
22
+
23
+ interface ButtonEntry {
24
+ readonly config: StatusToggleConfig
25
+ lastRaw: string | undefined
26
+ lastState: string | undefined
27
+ lastError: string | undefined
28
+ lastAt: number
29
+ lastPolledAt: number
30
+ }
31
+
32
+ const registry = new Map<string, ButtonEntry>()
33
+ let ctxRef: AddonServiceContext | undefined
34
+
35
+ const trim = (value: string): string => value.replace(/\s+$/, "").trim()
36
+
37
+ const pollButton = async (
38
+ entry: ButtonEntry,
39
+ ctx: AddonServiceContext,
40
+ ): Promise<ToggleState> => {
41
+ // ponytail: defaults are merged here so the global poller can use the
42
+ // per-button override without the schema forcing an `.default()` (which
43
+ // would erase the override path inside the union).
44
+ const timeoutMs = entry.config.timeoutMs ?? TOGGLE_DEFAULT_TIMEOUT_MS
45
+ try {
46
+ const res = await ctx.executor.run(entry.config.statusCommand, {
47
+ timeoutMs,
48
+ } as Parameters<typeof ctx.executor.run>[1])
49
+ const raw = trim(res.stdout ?? "")
50
+ const matchedState =
51
+ raw.length > 0 && entry.config.states[raw] !== undefined ? raw : undefined
52
+ return {
53
+ raw,
54
+ state: matchedState,
55
+ at: Date.now(),
56
+ }
57
+ } catch (err) {
58
+ return {
59
+ raw: "",
60
+ state: undefined,
61
+ error: err instanceof Error ? err.message : String(err),
62
+ at: Date.now(),
63
+ }
64
+ }
65
+ }
66
+
67
+ export const globalService: AddonGlobalService = {
68
+ methods: {
69
+ register: (buttonId: unknown, config: unknown): void => {
70
+ const id = String(buttonId)
71
+ const cfg = config as StatusToggleConfig
72
+ const existing = registry.get(id)
73
+ registry.set(id, {
74
+ config: cfg,
75
+ lastRaw: existing?.lastRaw,
76
+ lastState: existing?.lastState,
77
+ lastError: existing?.lastError,
78
+ lastAt: existing?.lastAt ?? 0,
79
+ lastPolledAt: existing?.lastPolledAt ?? 0,
80
+ })
81
+ void ctxRef?.poll("states")
82
+ },
83
+ unregister: (buttonId: unknown): void => {
84
+ registry.delete(String(buttonId))
85
+ },
86
+ // ponytail: tap side-channel. The per-button `onTap` calls this so the
87
+ // next poll happens before the global tick interval — keeps the deck in
88
+ // sync with the new state immediately after a user action.
89
+ // When buttonId is provided, resets that specific entry's lastPolledAt so
90
+ // the next global tick forces a fresh statusCommand run.
91
+ republish: (buttonId?: unknown): void => {
92
+ if (buttonId !== undefined) {
93
+ const entry = registry.get(String(buttonId))
94
+ if (entry !== undefined) {
95
+ entry.lastPolledAt = 0
96
+ }
97
+ }
98
+ void ctxRef?.poll("states")
99
+ },
100
+ // ponytail: used by the per-button tap to look up the matched state's
101
+ // `onTap` command without round-tripping through the registry copy. The
102
+ // poller keeps `lastState` fresh, so a stale read only happens on the
103
+ // first tap before the first poll completes.
104
+ lookup: (buttonId: unknown): ToggleState | null => {
105
+ const entry = registry.get(String(buttonId))
106
+ if (entry === undefined) return null
107
+ if (entry.lastAt === 0) return null
108
+ const out: ToggleState = {
109
+ raw: entry.lastRaw ?? "",
110
+ state: entry.lastState,
111
+ at: entry.lastAt,
112
+ }
113
+ return entry.lastError !== undefined
114
+ ? { ...out, error: entry.lastError }
115
+ : out
116
+ },
117
+ },
118
+ pollers: [
119
+ {
120
+ id: "states",
121
+ channel: TOGGLE_STATES_CHANNEL,
122
+ // ponytail: the global tick is bounded at 1s. Per-button cadence lives
123
+ // in `intervalMs` and is honored by `lastPolledAt`. Adding a longer
124
+ // global tick would just slow the first poll.
125
+ intervalMs: TOGGLE_POLL_TICK_MS,
126
+ poll: async (ctx: AddonServiceContext): Promise<ToggleStatesPayload> => {
127
+ const byButton: Record<string, ToggleState | null> = {}
128
+ if (registry.size === 0) return { byButton }
129
+ const now = Date.now()
130
+ await Promise.all(
131
+ [...registry.entries()].map(async ([buttonId, entry]) => {
132
+ const intervalMs =
133
+ entry.config.intervalMs ?? TOGGLE_DEFAULT_INTERVAL_MS
134
+ const due =
135
+ entry.lastPolledAt === 0 || now - entry.lastPolledAt >= intervalMs
136
+ if (!due) {
137
+ byButton[buttonId] =
138
+ entry.lastAt === 0
139
+ ? null
140
+ : entry.lastError !== undefined
141
+ ? {
142
+ raw: entry.lastRaw ?? "",
143
+ state: entry.lastState,
144
+ error: entry.lastError,
145
+ at: entry.lastAt,
146
+ }
147
+ : {
148
+ raw: entry.lastRaw ?? "",
149
+ state: entry.lastState,
150
+ at: entry.lastAt,
151
+ }
152
+ return
153
+ }
154
+ const next = await pollButton(entry, ctx)
155
+ entry.lastPolledAt = now
156
+ entry.lastAt = next.at
157
+ entry.lastRaw = next.raw
158
+ entry.lastState = next.state
159
+ entry.lastError = next.error
160
+ byButton[buttonId] = next
161
+ }),
162
+ )
163
+ return { byButton }
164
+ },
165
+ },
166
+ ],
167
+ onLoad: (ctx: AddonServiceContext) => {
168
+ ctxRef = ctx
169
+ },
170
+ onUnload: () => {
171
+ ctxRef = undefined
172
+ registry.clear()
173
+ },
174
+ }
@@ -0,0 +1,120 @@
1
+ import type { AddonManifestV1 } from "@/addon/api"
2
+ import { positionButtons } from "@/deck/position-buttons"
3
+
4
+ import actionBackend from "./buttons/action/backend"
5
+ import actionFrontend from "./buttons/action/frontend"
6
+ import changeDeckBackend from "./buttons/change-deck/backend"
7
+ import changeDeckFrontend from "./buttons/change-deck/frontend"
8
+ import mediaSampleBackend from "./buttons/media-sample/backend"
9
+ import mediaSampleFrontend from "./buttons/media-sample/frontend"
10
+ import pageNavBackend from "./buttons/page-nav/backend"
11
+ import pageNavFrontend from "./buttons/page-nav/frontend"
12
+ import toggleBackend from "./buttons/toggle/backend"
13
+ import toggleFrontend from "./buttons/toggle/frontend"
14
+ import { globalService as toggleGlobalService } from "./buttons/toggle/global-service"
15
+
16
+ export const manifest: AddonManifestV1 = {
17
+ apiVersion: 1,
18
+ name: "core",
19
+ buttonTypes: {
20
+ "core:action": {
21
+ frontend: actionFrontend,
22
+ // ponytail: gestureHandlers: ['tap'] is REQUIRED for type:// macros and any
23
+ // addon-deck button that uses actions.tap. The addon registry's default-deny
24
+ // policy strips undeclared handlers — without this, taps silently no-op.
25
+ service: { ...actionBackend, gestureHandlers: ["tap"] as const },
26
+ },
27
+ "core:change-deck": {
28
+ frontend: changeDeckFrontend,
29
+ service: { ...changeDeckBackend, gestureHandlers: ["tap"] as const },
30
+ },
31
+ "core:toggle": {
32
+ frontend: toggleFrontend,
33
+ service: { ...toggleBackend, gestureHandlers: ["tap"] as const },
34
+ },
35
+ "core:page-nav": {
36
+ frontend: pageNavFrontend,
37
+ service: { ...pageNavBackend, gestureHandlers: ["tap", "hold"] as const },
38
+ },
39
+ "core:media-sample": {
40
+ frontend: mediaSampleFrontend,
41
+ service: { ...mediaSampleBackend, gestureHandlers: ["tap"] as const },
42
+ },
43
+ },
44
+ globalService: toggleGlobalService,
45
+ decks: [
46
+ {
47
+ createDecks: ({ config, keyCount }) => {
48
+ const userButtons = (
49
+ config as { lockButtons?: ReadonlyArray<Record<string, unknown>> }
50
+ ).lockButtons
51
+
52
+ const centerButton = Math.floor(keyCount / 2)
53
+
54
+ // ponytail: default buttons omit `id` — the schema is `.strict()` and
55
+ // rejects unknown keys, and the runtime re-assigns `id` from `position`
56
+ // via `positionButtons` in run.ts. Spelling `id` here just emits
57
+ // "Unrecognized key: 'id'" warnings at startup (3 of them per daemon).
58
+ const defaultButtons = [
59
+ {
60
+ type: "date-time:date-time",
61
+ config: { format: "<strong><5xl>HH</5xl></strong>" },
62
+ position: centerButton - 1,
63
+ full: true,
64
+ },
65
+ {
66
+ type: "date-time:date-time",
67
+ config: { format: "<strong><5xl><blink>:</blink></5xl></strong>" },
68
+ position: centerButton,
69
+ full: true,
70
+ },
71
+ {
72
+ type: "date-time:date-time",
73
+ config: { format: "<strong><5xl>mm</5xl></strong>" },
74
+ position: centerButton + 1,
75
+ full: true,
76
+ },
77
+ ]
78
+
79
+ return {
80
+ "core:lock": {
81
+ name: "Lock",
82
+ buttons:
83
+ userButtons !== undefined && userButtons.length > 0
84
+ ? positionButtons(
85
+ userButtons as Array<{ position?: number; id?: string }>,
86
+ keyCount,
87
+ ).map((b, i) => {
88
+ // ponytail: strip the user-supplied `id` (if any) before
89
+ // spreading. The button schema is `.strict()` and rejects
90
+ // unknown keys; without this, the runtime emits
91
+ // "Unrecognized key: 'id'" warnings for each user button.
92
+ const { id: _userId, ...rest } = b
93
+ return {
94
+ id:
95
+ b.position !== undefined ? String(b.position) : `b${i}`,
96
+ ...rest,
97
+ }
98
+ })
99
+ : defaultButtons,
100
+ },
101
+ }
102
+ },
103
+ },
104
+ ],
105
+ }
106
+
107
+ export const coreAddon = manifest
108
+ export default manifest
109
+ export {
110
+ actionBackend as actionButtonBackend,
111
+ actionFrontend as ActionButtonFrontend,
112
+ changeDeckBackend as changeDeckButtonBackend,
113
+ changeDeckFrontend as ChangeDeckFrontend,
114
+ mediaSampleBackend as mediaSampleButtonBackend,
115
+ mediaSampleFrontend as MediaSampleButtonFrontend,
116
+ pageNavBackend as pageNavButtonBackend,
117
+ pageNavFrontend as PageNavFrontend,
118
+ toggleBackend as toggleButtonBackend,
119
+ toggleFrontend as ToggleButtonFrontend,
120
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "kind": "addon",
3
+ "apiVersion": 1,
4
+ "name": "core",
5
+ "entry": "index.ts"
6
+ }
@@ -0,0 +1,73 @@
1
+ # date-time
2
+
3
+ Time + date buttons. All refresh on a 1-second interval.
4
+
5
+ ## Buttons
6
+
7
+ | Type | Description |
8
+ | ------------------------ | ------------------------------------------- |
9
+ | `date-time:time` | Digital time (HH:mm or big variant) |
10
+ | `date-time:date` | Day + month + weekday |
11
+ | `date-time:date-time` | Combined date + time (custom format string) |
12
+ | `date-time:analog-clock` | SVG analog clock face |
13
+
14
+ ## Config
15
+
16
+ ### `date-time:time`
17
+
18
+ ```yaml
19
+ - position: 2
20
+ type: date-time:time
21
+ config:
22
+ variant: big # "default" (HH:mm) or "big" (HH.mm)
23
+ ```
24
+
25
+ ### `date-time:date`
26
+
27
+ ```yaml
28
+ - position: 3
29
+ type: date-time:date
30
+ config:
31
+ locale: en-US # optional, defaults to "en-US"
32
+ time_zone: Europe/Madrid # optional, defaults to local
33
+ ```
34
+
35
+ ### `date-time:date-time`
36
+
37
+ ```yaml
38
+ - position: 5
39
+ type: date-time:date-time
40
+ config:
41
+ format: "DD/MM/YYYY HH:mm:ss" # default; supports <markup> tags
42
+ ```
43
+
44
+ ### `date-time:analog-clock`
45
+
46
+ ```yaml
47
+ - position: 4
48
+ type: date-time:analog-clock # no config
49
+ ```
50
+
51
+ ## Example
52
+
53
+ ```yaml
54
+ decks:
55
+ main:
56
+ name: Main
57
+ buttons:
58
+ - position: 2
59
+ type: date-time:time
60
+ config: { variant: big }
61
+ - position: 3
62
+ type: date-time:date
63
+ - position: 4
64
+ type: date-time:analog-clock
65
+ - position: 5
66
+ type: date-time:date-time
67
+ config:
68
+ format: "YYYY-MM-DD HH:mm"
69
+ ```
70
+
71
+ ## See also
72
+
73
+ - [system-status](../system-status/README.md) — uptime in the status button
@@ -0,0 +1,10 @@
1
+ import type { AddonButtonTypeService } from "@/addon/api"
2
+
3
+ import { configSchema } from "./config"
4
+
5
+ export const ANALOG_CLOCK_INTERVAL_MS = 1000
6
+
7
+ export default {
8
+ configSchema,
9
+ defaultRenderIntervalMs: ANALOG_CLOCK_INTERVAL_MS,
10
+ } satisfies AddonButtonTypeService
@@ -0,0 +1,4 @@
1
+ import { z } from "zod"
2
+
3
+ export const configSchema = z.object({})
4
+ export type ConfigSchema = z.infer<typeof configSchema>
@@ -0,0 +1,88 @@
1
+ import type { AddonFrontendButton } from "@/addon/api"
2
+
3
+ import { useNow } from "../../shared/use-now"
4
+ import { ConfigSchema } from "./config"
5
+
6
+ const polar = (
7
+ cx: number,
8
+ cy: number,
9
+ r: number,
10
+ deg: number,
11
+ ): { x: number; y: number } => {
12
+ const rad = ((deg - 90) * Math.PI) / 180
13
+ return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) }
14
+ }
15
+
16
+ const INTERVAL_MS = 1000
17
+
18
+ const AnalogClockButtonFrontend: AddonFrontendButton<ConfigSchema> = () => {
19
+ const now = useNow(INTERVAL_MS)
20
+ const h = now.getHours() % 12
21
+ const m = now.getMinutes()
22
+ const s = now.getSeconds()
23
+ const hourAngle = (h + m / 60) * 30
24
+ const minuteAngle = (m + s / 60) * 6
25
+ const secondAngle = s * 6
26
+ const hourEnd = polar(50, 50, 22, hourAngle)
27
+ const minEnd = polar(50, 50, 32, minuteAngle)
28
+ const secEnd = polar(50, 50, 36, secondAngle)
29
+ const ticks = Array.from({ length: 12 }, (_, i) => {
30
+ const angle = i * 30
31
+ const outer = polar(50, 50, 40, angle)
32
+ const inner = polar(50, 50, i % 3 === 0 ? 34 : 37, angle)
33
+ return (
34
+ <line
35
+ key={i}
36
+ x1={outer.x}
37
+ y1={outer.y}
38
+ x2={inner.x}
39
+ y2={inner.y}
40
+ stroke="var(--sireno-color-muted)"
41
+ strokeWidth={i % 3 === 0 ? 1.5 : 0.75}
42
+ />
43
+ )
44
+ })
45
+ return (
46
+ <svg viewBox="0 0 100 100" className="h-full w-full">
47
+ <circle
48
+ cx="50"
49
+ cy="50"
50
+ r="42"
51
+ fill="none"
52
+ stroke="var(--sireno-color-primary)"
53
+ strokeWidth={1}
54
+ />
55
+ {ticks}
56
+ <line
57
+ x1="50"
58
+ y1="50"
59
+ x2={hourEnd.x}
60
+ y2={hourEnd.y}
61
+ stroke="var(--sireno-color-fg)"
62
+ strokeWidth={3}
63
+ strokeLinecap="round"
64
+ />
65
+ <line
66
+ x1="50"
67
+ y1="50"
68
+ x2={minEnd.x}
69
+ y2={minEnd.y}
70
+ stroke="var(--sireno-color-fg)"
71
+ strokeWidth={2}
72
+ strokeLinecap="round"
73
+ />
74
+ <line
75
+ x1="50"
76
+ y1="50"
77
+ x2={secEnd.x}
78
+ y2={secEnd.y}
79
+ stroke="var(--sireno-color-accent)"
80
+ strokeWidth={1}
81
+ strokeLinecap="round"
82
+ />
83
+ <circle cx="50" cy="50" r="2" fill="var(--sireno-color-fg)" />
84
+ </svg>
85
+ )
86
+ }
87
+
88
+ export default AnalogClockButtonFrontend
@@ -0,0 +1,10 @@
1
+ import type { AddonButtonTypeService } from "@/addon/api"
2
+
3
+ import { configSchema } from "./config"
4
+
5
+ export const DIGITAL_DATE_TIME_INTERVAL_MS = 1000
6
+
7
+ export default {
8
+ configSchema,
9
+ defaultRenderIntervalMs: DIGITAL_DATE_TIME_INTERVAL_MS,
10
+ } satisfies AddonButtonTypeService
@@ -0,0 +1,9 @@
1
+ import { z } from "zod"
2
+
3
+ export const configSchema = z
4
+ .object({
5
+ format: z.string().min(1).optional().default("DD/MM/YYYY HH:mm:ss"),
6
+ })
7
+ .strict()
8
+
9
+ export type ConfigSchema = z.infer<typeof configSchema>
@@ -0,0 +1,26 @@
1
+ import type { AddonFrontendButton } from "@/addon/api"
2
+ import { Text } from "@/ui/index"
3
+
4
+ import { formatDigitalDateTimeLabel } from "../../shared/format"
5
+ import { useNow } from "../../shared/use-now"
6
+ import { ConfigSchema } from "./config"
7
+
8
+ const INTERVAL_MS = 1000
9
+
10
+ const DateTimeButtonFrontend: AddonFrontendButton<ConfigSchema> = ({
11
+ config,
12
+ }) => {
13
+ const now = useNow(INTERVAL_MS)
14
+ const format = (config as { format?: string }).format ?? "DD/MM/YYYY HH:mm:ss"
15
+ return (
16
+ <span className="flex h-full w-full items-center justify-center">
17
+ <Text
18
+ size="lg"
19
+ tone="fg"
20
+ text={formatDigitalDateTimeLabel(format, now)}
21
+ />
22
+ </span>
23
+ )
24
+ }
25
+
26
+ export default DateTimeButtonFrontend
@@ -0,0 +1,10 @@
1
+ import type { AddonButtonTypeService } from "@/addon/api"
2
+
3
+ import { configSchema } from "./config"
4
+
5
+ export const DATE_BUTTON_INTERVAL_MS = 60000
6
+
7
+ export default {
8
+ configSchema,
9
+ defaultRenderIntervalMs: DATE_BUTTON_INTERVAL_MS,
10
+ } satisfies AddonButtonTypeService
@@ -0,0 +1,10 @@
1
+ import { z } from "zod"
2
+
3
+ export const configSchema = z
4
+ .object({
5
+ locale: z.string().min(2).max(35).optional(),
6
+ time_zone: z.string().min(1).optional(),
7
+ })
8
+ .strict()
9
+
10
+ export type ConfigSchema = z.infer<typeof configSchema>
@@ -0,0 +1,42 @@
1
+ import type { AddonFrontendButton } from "@/addon/api"
2
+
3
+ import { Chip, Text } from "@/ui"
4
+ import { formatDateParts } from "../../shared/format-date"
5
+ import { useNow } from "../../shared/use-now"
6
+ import { ConfigSchema } from "./config"
7
+
8
+ const INTERVAL_MS = 60000
9
+
10
+ const DateButtonFrontend: AddonFrontendButton<ConfigSchema> = ({ config }) => {
11
+ const now = useNow(INTERVAL_MS)
12
+ const { day, month, weekday, year } = formatDateParts(
13
+ {
14
+ ...config,
15
+ weekDayFormat: "short",
16
+ yearFormat: "2-digit",
17
+ },
18
+ now,
19
+ )
20
+ return (
21
+ <span className="flex h-full w-full flex-col items-center justify-center gap-0.5">
22
+ <Chip tone="primary" size="md" text={month} />
23
+ <Text
24
+ size="4xl"
25
+ lineHeight="1em"
26
+ tone="fg"
27
+ typography="main"
28
+ weight="bold"
29
+ text={day}
30
+ />
31
+ <Text
32
+ tone="muted"
33
+ size="md"
34
+ typography="main"
35
+ weight="semibold"
36
+ text={weekday}
37
+ />
38
+ </span>
39
+ )
40
+ }
41
+
42
+ export default DateButtonFrontend
@@ -0,0 +1,10 @@
1
+ import type { AddonButtonTypeService } from "@/addon/api"
2
+
3
+ import { configSchema } from "./config"
4
+
5
+ export const TIME_BUTTON_INTERVAL_MS = 1000
6
+
7
+ export default {
8
+ configSchema,
9
+ defaultRenderIntervalMs: TIME_BUTTON_INTERVAL_MS,
10
+ } satisfies AddonButtonTypeService
@@ -0,0 +1,9 @@
1
+ import { z } from "zod"
2
+
3
+ export const configSchema = z
4
+ .object({
5
+ variant: z.enum(["default", "big"]).optional().default("default"),
6
+ })
7
+ .strict()
8
+
9
+ export type ConfigSchema = z.infer<typeof configSchema>