@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,271 @@
1
+ import { dirname } from "node:path"
2
+
3
+ import type { DeckConfigMessage } from "@/api/protocol-internal"
4
+ import type { RuntimeDeck } from "@/deck"
5
+ import { isSystemButtonType } from "@/deck/system-buttons/types"
6
+ import { computeSystemButtonForSlotN1 } from "@/deck/system-back-injection"
7
+ import {
8
+ resolveIconSource,
9
+ type ResolveIconPathOptions,
10
+ } from "@/render/icon-source-resolver"
11
+
12
+ export interface AddonFrontendRef {
13
+ readonly name: string
14
+ readonly frontendEntry: string | null
15
+ }
16
+
17
+ export const buildResolverOptions = (
18
+ addonByType: ReadonlyMap<string, AddonFrontendRef>,
19
+ baseDirs: ReadonlyArray<string>,
20
+ // ponytail: external addons (loaded from config's addons: list) need their
21
+ // dirs registered so `addon://<name>/assets/icon.png` resolves. The basenames
22
+ // match the addon names in deck triggers.
23
+ extraAddonDirs?: ReadonlyMap<string, string>,
24
+ ): ResolveIconPathOptions => {
25
+ const addonDirs = new Map<string, string>()
26
+ for (const ref of addonByType.values()) {
27
+ if (ref.frontendEntry !== null) {
28
+ addonDirs.set(ref.name, dirname(ref.frontendEntry))
29
+ }
30
+ }
31
+ for (const [name, dir] of extraAddonDirs ?? []) {
32
+ addonDirs.set(name, dir)
33
+ }
34
+ return { addonDirs, baseDirs }
35
+ }
36
+
37
+ export type AssetLookup = (fullPath: string) => string | undefined
38
+
39
+ const resolveOne = (
40
+ icon: unknown,
41
+ resolverOptions: ResolveIconPathOptions,
42
+ assetLookup: AssetLookup,
43
+ ): unknown => {
44
+ if (typeof icon !== "string") return icon
45
+ if (icon.startsWith("icon://")) return icon
46
+ if (icon.startsWith("asset://")) return icon
47
+ let resolved
48
+ try {
49
+ resolved = resolveIconSource(icon, resolverOptions)
50
+ } catch {
51
+ return icon
52
+ }
53
+ if (resolved.kind !== "asset") return icon
54
+ const id = assetLookup(resolved.fullPath)
55
+ if (id === undefined) return icon
56
+ return `asset://${id}`
57
+ }
58
+
59
+ export const resolveConfigIcons = (
60
+ cfg: Record<string, unknown>,
61
+ resolverOptions: ResolveIconPathOptions,
62
+ assetLookup: AssetLookup,
63
+ ): Record<string, unknown> => {
64
+ const next = { ...cfg }
65
+ if ("icon" in next)
66
+ next.icon = resolveOne(next.icon, resolverOptions, assetLookup)
67
+ if (Array.isArray(next.lines)) {
68
+ next.lines = (next.lines as ReadonlyArray<unknown>).map((line) => {
69
+ if (typeof line !== "object" || line === null) return line
70
+ const lineObj = line as Record<string, unknown>
71
+ if (!("icon" in lineObj)) return line
72
+ return {
73
+ ...lineObj,
74
+ icon: resolveOne(lineObj.icon, resolverOptions, assetLookup),
75
+ }
76
+ })
77
+ }
78
+ return next
79
+ }
80
+
81
+ const deriveLabel = (
82
+ type: string,
83
+ config: Record<string, unknown>,
84
+ ): string | undefined => {
85
+ switch (type) {
86
+ case "core:action": {
87
+ const cmd = config["command"]
88
+ if (typeof cmd === "string" && cmd.length > 0) {
89
+ return cmd.length > 14 ? `${cmd.slice(0, 13)}…` : cmd
90
+ }
91
+ // ponytail: fallback to config.label so addon-deck buttons (e.g.
92
+ // chrome-overlay's {label: 'New Tab'}) render their label when no
93
+ // command is set. The legacy config-command path stays primary.
94
+ const label = config["label"]
95
+ if (typeof label === "string" && label.length > 0) {
96
+ return label
97
+ }
98
+ return undefined
99
+ }
100
+ case "core:change-deck": {
101
+ const deck = config["deck"]
102
+ if (typeof deck === "string" && deck.length > 0) {
103
+ return `→ ${deck}`
104
+ }
105
+ return undefined
106
+ }
107
+ default:
108
+ return undefined
109
+ }
110
+ }
111
+
112
+ export const buildDeckConfigMessage = (
113
+ deck: RuntimeDeck,
114
+ addonByType: Map<string, AddonFrontendRef>,
115
+ resolverOptions: ResolveIconPathOptions = {},
116
+ navState?: {
117
+ navStackDepth: number
118
+ hasOverlayDeckAvailable: boolean
119
+ inOverlayMode?: boolean
120
+ },
121
+ keyCount?: number,
122
+ isCompact?: boolean,
123
+ assetLookup: AssetLookup = () => undefined,
124
+ overlayDeckIcon: string | null = null,
125
+ overlayDeckName: string | null = null,
126
+ options?: { lockActive?: boolean },
127
+ ): DeckConfigMessage => {
128
+ const n1Position = keyCount !== undefined ? keyCount - 1 : -1
129
+ const buttons = deck.buttons
130
+ .filter((b) => {
131
+ if (options?.lockActive !== true) return true
132
+ if (b.position !== n1Position) return true
133
+ return !isSystemButtonType(b.type)
134
+ })
135
+ .map((b) => {
136
+ const position = b.position
137
+ const addon = addonByType.get(b.type)
138
+ const cfg = (b.config ?? {}) as Record<string, unknown>
139
+ const label = deriveLabel(b.type, cfg)
140
+ const resolvedConfig = resolveConfigIcons(
141
+ cfg,
142
+ resolverOptions,
143
+ assetLookup,
144
+ )
145
+ return {
146
+ id: b.id,
147
+ type: b.type,
148
+ ...(Number.isFinite(position) ? { position } : {}),
149
+ config: resolvedConfig,
150
+ ...(label !== undefined ? { label } : {}),
151
+ ...(addon !== undefined ? { addonName: addon.name } : {}),
152
+ ...(addon?.frontendEntry !== undefined && addon.frontendEntry !== null
153
+ ? { frontendEntry: addon.frontendEntry }
154
+ : {}),
155
+ ...(b.full === true ? { full: true } : {}),
156
+ ...(b.variant !== undefined && b.variant.length > 0
157
+ ? { variant: b.variant }
158
+ : {}),
159
+ ...(b.buttonColor !== undefined ? { buttonColor: b.buttonColor } : {}),
160
+ }
161
+ })
162
+
163
+ let finalButtons = buttons
164
+ if (n1Position >= 0 && options?.lockActive !== true) {
165
+ const systemBtn = computeSystemButtonForSlotN1(deck, {
166
+ navStackDepth: navState?.navStackDepth ?? 1,
167
+ hasOverlayDeckAvailable: navState?.hasOverlayDeckAvailable ?? false,
168
+ lockActive: options?.lockActive,
169
+ inOverlayMode: navState?.inOverlayMode,
170
+ })
171
+ if (systemBtn !== null) {
172
+ const hasN1 = buttons.some(
173
+ (b) => b.position === n1Position && isSystemButtonType(b.type),
174
+ )
175
+ if (hasN1) {
176
+ finalButtons = buttons.map((b) =>
177
+ b.position === n1Position && isSystemButtonType(b.type)
178
+ ? { ...b, type: systemBtn }
179
+ : b,
180
+ )
181
+ } else {
182
+ finalButtons = [
183
+ ...buttons,
184
+ {
185
+ id: `${n1Position}-${deck.id}-0`,
186
+ type: systemBtn,
187
+ position: n1Position,
188
+ config: {},
189
+ },
190
+ ]
191
+ }
192
+ }
193
+ }
194
+
195
+ const resolvedOverlayIcon =
196
+ overlayDeckIcon === null
197
+ ? null
198
+ : (resolveOne(overlayDeckIcon, resolverOptions, assetLookup) as
199
+ | string
200
+ | null)
201
+ return {
202
+ type: "deck-config",
203
+ deckId: deck.id,
204
+ surfaces: {
205
+ [deck.id]: {
206
+ id: deck.id,
207
+ name: deck.name ?? deck.id,
208
+ buttons: finalButtons,
209
+ ...(deck.buttonColor !== undefined
210
+ ? { buttonColor: deck.buttonColor }
211
+ : {}),
212
+ ...(deck.variant !== undefined && deck.variant.length > 0
213
+ ? { variant: deck.variant }
214
+ : {}),
215
+ ...(deck.buttonErrors !== undefined && deck.buttonErrors.length > 0
216
+ ? {
217
+ buttonErrors: deck.buttonErrors.map((e) => ({
218
+ position: e.position,
219
+ expiresAt: Number.MAX_SAFE_INTEGER,
220
+ ...(e.buttonId !== undefined ? { buttonId: e.buttonId } : {}),
221
+ details: e.details,
222
+ })),
223
+ }
224
+ : {}),
225
+ },
226
+ },
227
+ navMode: "regular",
228
+ isCompact: isCompact ?? false,
229
+ hasOverlayDeckAvailable: navState?.hasOverlayDeckAvailable ?? false,
230
+ overlayDeckIcon: resolvedOverlayIcon,
231
+ overlayDeckName,
232
+ }
233
+ }
234
+
235
+ export type DeckTreeEntry = {
236
+ readonly id: string
237
+ readonly name: string
238
+ readonly isOverlay: boolean
239
+ readonly links: Array<{
240
+ readonly target: string
241
+ readonly label?: string
242
+ }>
243
+ }
244
+
245
+ export const buildDeckTree = (
246
+ decks: ReadonlyArray<RuntimeDeck>,
247
+ mainDeckId: string,
248
+ ): { rootId: string; decks: DeckTreeEntry[] } => {
249
+ const entries: DeckTreeEntry[] = decks.map((deck) => {
250
+ const links: { target: string; label?: string }[] = []
251
+ for (const btn of deck.buttons ?? []) {
252
+ if (btn.type === "core:change-deck") {
253
+ const config = btn.config as
254
+ | { deck?: string; label?: string }
255
+ | undefined
256
+ if (config?.deck !== undefined) {
257
+ links.push({ target: config.deck, label: config.label })
258
+ }
259
+ }
260
+ }
261
+ return {
262
+ id: deck.id,
263
+ name: deck.name ?? deck.id,
264
+ isOverlay:
265
+ (deck.processNames?.length ?? 0) > 0 ||
266
+ (deck.windowNames?.length ?? 0) > 0,
267
+ links,
268
+ }
269
+ })
270
+ return { rootId: mainDeckId, decks: entries }
271
+ }
@@ -0,0 +1,87 @@
1
+ import type { RuntimeDeck, RuntimeButton } from "./runtime"
2
+ import { paginationReservedPositions } from "@/core/pagination"
3
+ import { computeSystemButtonForSlotN1 } from "./system-back-injection"
4
+
5
+ export type EditorMutationCapability = "update" | "delete" | "reorder"
6
+
7
+ export interface EditorSourceTarget {
8
+ readonly sourcePath: string
9
+ readonly sourceDeckId: string
10
+ readonly sourceButtonIndex: number
11
+ readonly sourceButtonPath: string
12
+ readonly fingerprint: string
13
+ readonly capability: EditorMutationCapability
14
+ }
15
+
16
+ export interface EditorAddonOwner {
17
+ readonly addonIndex: number
18
+ readonly addonName: string
19
+ readonly overrideKey: string
20
+ readonly capabilities: ReadonlyArray<string>
21
+ }
22
+
23
+ export interface EditorSurfaceButton {
24
+ readonly id: string
25
+ readonly type: string
26
+ readonly position: number
27
+ readonly sourceTarget: EditorSourceTarget | null
28
+ }
29
+
30
+ export interface EditorSurfaceDescriptor {
31
+ readonly id: string
32
+ readonly sourceDeckId: string
33
+ readonly projectionId: string
34
+ readonly pageIndex: number
35
+ readonly isOverlay: boolean
36
+ readonly editable: boolean
37
+ readonly addonOwner: EditorAddonOwner | null
38
+ readonly reservedPositions: number[]
39
+ readonly buttons: EditorSurfaceButton[]
40
+ }
41
+
42
+ export interface DescribeEditorSurfacesOptions {
43
+ readonly decks: ReadonlyArray<RuntimeDeck>
44
+ readonly keyCount: number
45
+ readonly revision: number
46
+ readonly systemState?: {
47
+ navStackDepth: number
48
+ hasOverlayDeckAvailable: boolean
49
+ lockActive?: boolean
50
+ inOverlayMode?: boolean
51
+ }
52
+ }
53
+
54
+ export const describeEditorSurfaces = ({
55
+ decks,
56
+ keyCount,
57
+ revision: _revision,
58
+ systemState,
59
+ }: DescribeEditorSurfacesOptions): EditorSurfaceDescriptor[] =>
60
+ decks.map((deck) => {
61
+ const systemType = computeSystemButtonForSlotN1(deck, {
62
+ navStackDepth: systemState?.navStackDepth ?? 1,
63
+ hasOverlayDeckAvailable: systemState?.hasOverlayDeckAvailable ?? false,
64
+ lockActive: systemState?.lockActive,
65
+ inOverlayMode: systemState?.inOverlayMode,
66
+ })
67
+ const reservedPositions = new Set(
68
+ paginationReservedPositions(keyCount, deck.paginated === true),
69
+ )
70
+ if (systemType !== null) reservedPositions.add(keyCount - 1)
71
+ return {
72
+ id: deck.id,
73
+ sourceDeckId: deck.sourceDeckId ?? deck.id,
74
+ projectionId: deck.projectionId ?? deck.id,
75
+ pageIndex: deck.pageIndex ?? 0,
76
+ isOverlay: deck.isOverlay === true || deck.isOverlayDeck === true,
77
+ editable: deck.editable === true,
78
+ addonOwner: deck.addonOwner ?? null,
79
+ reservedPositions: [...reservedPositions].sort((a, b) => a - b),
80
+ buttons: deck.buttons.map((button: RuntimeButton) => ({
81
+ id: button.id,
82
+ type: button.type,
83
+ position: button.position ?? -1,
84
+ sourceTarget: button.sourceTarget ?? null,
85
+ })),
86
+ }
87
+ })
@@ -0,0 +1,18 @@
1
+ import { hostname, platform, arch, userInfo } from "node:os"
2
+
3
+ export interface HostContext {
4
+ hostname: string
5
+ platform: NodeJS.Platform
6
+ userInfo: { username: string; homedir: string }
7
+ arch: string
8
+ }
9
+
10
+ export const getHostContext = (): HostContext => {
11
+ const info = userInfo()
12
+ return {
13
+ hostname: hostname(),
14
+ platform: platform(),
15
+ userInfo: { username: info.username, homedir: info.homedir },
16
+ arch: arch(),
17
+ }
18
+ }
@@ -0,0 +1,102 @@
1
+ import type pino from "pino"
2
+
3
+ import { createPubSub } from "@/core/pub-sub"
4
+ import { createStore } from "@/core/store"
5
+ import { NotImplementedError } from "@/util/errors"
6
+ import { createLogger } from "@/util/logger"
7
+ import type { KeyMacroProvider } from "@/system/providers/key-macro"
8
+
9
+ import { createActionExecutor } from "@/action/executor"
10
+ import { getHostContext } from "./host-context"
11
+ import { createMethods } from "./methods"
12
+ import { createRuntime, type Runtime, type RuntimeDeck } from "./runtime"
13
+
14
+ export { createActionExecutor, type ActionExecutor } from "@/action/executor"
15
+ export type { PubSub } from "@/core/pub-sub"
16
+ export type { Store } from "@/core/store"
17
+ export {
18
+ createMethods,
19
+ type Methods,
20
+ type MethodsContext,
21
+ type KeyMacroAction,
22
+ } from "./methods"
23
+ export {
24
+ createRuntime,
25
+ type Runtime,
26
+ type RuntimeDeck,
27
+ type RuntimeButton,
28
+ type RuntimeButtonHandler,
29
+ type ButtonActionContext,
30
+ type GestureEvent,
31
+ type GestureListener,
32
+ type MountedButton,
33
+ } from "./runtime"
34
+ export { getHostContext, type HostContext } from "./host-context"
35
+ export {
36
+ computeSystemButtonForSlotN1,
37
+ injectSystemButtons,
38
+ } from "./system-back-injection"
39
+ export { parseMacro } from "./macro-parse"
40
+ export {
41
+ describeEditorSurfaces,
42
+ type EditorAddonOwner,
43
+ type EditorMutationCapability,
44
+ type EditorSourceTarget,
45
+ type EditorSurfaceButton,
46
+ type EditorSurfaceDescriptor,
47
+ } from "./editor-surfaces"
48
+ export {
49
+ isSystemButtonType,
50
+ SYSTEM_BUTTON_TYPES,
51
+ type SystemButtonType,
52
+ } from "./system-buttons/types"
53
+
54
+ export interface CreateDeckRuntimeOptions {
55
+ decks: ReadonlyArray<RuntimeDeck>
56
+ logger?: pino.Logger
57
+ keyMacroProvider?: KeyMacroProvider
58
+ }
59
+
60
+ export const createDeckRuntime = (
61
+ options: CreateDeckRuntimeOptions,
62
+ ): {
63
+ runtime: Runtime
64
+ methods: ReturnType<typeof createMethods>
65
+ pubSub: ReturnType<typeof createPubSub>
66
+ store: ReturnType<typeof createStore>
67
+ } => {
68
+ const logger = options.logger ?? createLogger({ level: "silent" })
69
+ const pubSub = createPubSub()
70
+ const store = createStore()
71
+ const executor = createActionExecutor({ host: getHostContext() })
72
+
73
+ const methodsRef: { current: ReturnType<typeof createMethods> | undefined } =
74
+ {
75
+ current: undefined,
76
+ }
77
+
78
+ const runtime = createRuntime({
79
+ decks: options.decks,
80
+ pubSub,
81
+ store,
82
+ logger,
83
+ getMethods: () => methodsRef.current!,
84
+ })
85
+
86
+ const methods = createMethods({
87
+ runtime,
88
+ pubSub,
89
+ store,
90
+ executor,
91
+ logger,
92
+ ...(options.keyMacroProvider !== undefined
93
+ ? { keyMacroProvider: options.keyMacroProvider }
94
+ : {}),
95
+ })
96
+
97
+ methodsRef.current = methods
98
+
99
+ return { runtime, methods, pubSub, store }
100
+ }
101
+
102
+ export { NotImplementedError }
@@ -0,0 +1,182 @@
1
+ import { parseCombo } from "@/system/providers/key-macro/parser"
2
+
3
+ export type MacroStep =
4
+ | { kind: "combo"; value: string }
5
+ | { kind: "key"; value: string }
6
+ | { kind: "text"; value: string }
7
+ | { kind: "delay"; ms: number }
8
+
9
+ const DELAY_RE = /^(\d+)(ms|s|m|h)$/
10
+
11
+ const parseDelay = (raw: string): number | null => {
12
+ const m = raw.match(DELAY_RE)
13
+ if (m === null) return null
14
+ const n = Number(m[1])
15
+ const unit = m[2]
16
+ if (unit === "ms") return n
17
+ if (unit === "s") return n * 1000
18
+ if (unit === "m") return n * 60_000
19
+ if (unit === "h") return n * 3_600_000
20
+ return null
21
+ }
22
+
23
+ export const parseMacro = (value: string): MacroStep[] => {
24
+ const segments = value
25
+ .split(";")
26
+ .map((s) => s.trim())
27
+ .filter((s) => s.length > 0)
28
+ const steps: MacroStep[] = []
29
+ for (const seg of segments) {
30
+ const lc = seg.toLowerCase()
31
+ if (lc.startsWith("delay(") && lc.endsWith(")")) {
32
+ const inner = lc.slice(6, -1)
33
+ const ms = parseDelay(inner)
34
+ if (ms !== null) {
35
+ steps.push({ kind: "delay", ms })
36
+ continue
37
+ }
38
+ }
39
+ const parsed = parseCombo(seg)
40
+ if (parsed !== null) {
41
+ const combo =
42
+ parsed.mods.length > 0
43
+ ? `${parsed.mods.join("+")}+${parsed.key}`
44
+ : parsed.key
45
+ steps.push({ kind: "combo", value: combo })
46
+ continue
47
+ }
48
+ steps.push({ kind: "text", value: seg })
49
+ }
50
+ return steps
51
+ }
52
+
53
+ export type MacroPlatform = "macos" | "linux" | "windows"
54
+
55
+ /**
56
+ * Spellings accepted for a platform override. `osx` and `darwin` are here
57
+ * because the older JSON macro form and `process.platform` use them
58
+ * respectively — a user should not have to know which layer they are talking
59
+ * to in order to name their own operating system.
60
+ */
61
+ const PLATFORM_ALIASES: ReadonlyMap<string, MacroPlatform> = new Map([
62
+ ["macos", "macos"],
63
+ ["mac", "macos"],
64
+ ["osx", "macos"],
65
+ ["darwin", "macos"],
66
+ ["linux", "linux"],
67
+ ["windows", "windows"],
68
+ ["win", "windows"],
69
+ ["win32", "windows"],
70
+ ])
71
+
72
+ export const currentMacroPlatform = (
73
+ platform: string = process.platform,
74
+ ): MacroPlatform => {
75
+ if (platform === "darwin") return "macos"
76
+ if (platform === "win32") return "windows"
77
+ return "linux"
78
+ }
79
+
80
+ export interface PlatformMacro {
81
+ readonly overrides: ReadonlyMap<MacroPlatform, string>
82
+ /** The macro used by any platform without an override. Always present. */
83
+ readonly fallback: string
84
+ }
85
+
86
+ export class MacroSyntaxError extends Error {}
87
+
88
+ /**
89
+ * Parses `[os:override][os2:override2]default` into its parts.
90
+ *
91
+ * Overrides are a prefix run: parsing stops at the first character that is not
92
+ * the start of a well-formed `[<known-os>:` block, and everything from there on
93
+ * is the default verbatim. That keeps every macro that does not use the syntax
94
+ * working untouched, including ones containing `]` — `macro://ctrl+]` never
95
+ * enters bracket parsing because it does not begin with `[`.
96
+ *
97
+ * The consequence is that a literal `]` INSIDE an override would close it
98
+ * early, so it must be written with its key name, `bracketright`. The default
99
+ * segment has no such restriction.
100
+ */
101
+ export const parsePlatformMacro = (value: string): PlatformMacro => {
102
+ const overrides = new Map<MacroPlatform, string>()
103
+ let rest = value
104
+
105
+ while (rest.startsWith("[")) {
106
+ const colon = rest.indexOf(":")
107
+ if (colon === -1) break
108
+ const rawName = rest.slice(1, colon).trim().toLowerCase()
109
+ const platform = PLATFORM_ALIASES.get(rawName)
110
+ // Not a platform override — e.g. a macro that genuinely starts with "[".
111
+ // Leave it, and everything after it, as the default.
112
+ if (platform === undefined) break
113
+ const close = rest.indexOf("]", colon)
114
+ if (close === -1) {
115
+ throw new MacroSyntaxError(
116
+ `macro: unterminated '[${rawName}:' override — add the closing ']'`,
117
+ )
118
+ }
119
+ if (overrides.has(platform)) {
120
+ throw new MacroSyntaxError(`macro: duplicate override for '${platform}'`)
121
+ }
122
+ const override = rest.slice(colon + 1, close).trim()
123
+ if (override.length === 0) {
124
+ throw new MacroSyntaxError(`macro: override for '${platform}' is empty`)
125
+ }
126
+ overrides.set(platform, override)
127
+ rest = rest.slice(close + 1)
128
+ }
129
+
130
+ const fallback = rest.trim()
131
+ if (fallback.length === 0) {
132
+ // Deliberately mandatory: without it a macro would silently do nothing on
133
+ // any platform the author did not think to list.
134
+ throw new MacroSyntaxError(
135
+ overrides.size > 0
136
+ ? "macro: a default is required after the per-OS overrides, e.g. macro://[macos:cmd+c]ctrl+c"
137
+ : "macro: requires a value, e.g. macro://ctrl+c",
138
+ )
139
+ }
140
+ return { overrides, fallback }
141
+ }
142
+
143
+ /**
144
+ * Picks the macro this platform should run. Platforms without an override get
145
+ * the default, which is what makes `[windows:X]Y` mean "X on Windows, Y on
146
+ * macOS and Linux".
147
+ */
148
+ export const resolvePlatformMacro = (
149
+ value: string,
150
+ platform: string = process.platform,
151
+ ): string => {
152
+ const parsed = parsePlatformMacro(value)
153
+ return parsed.overrides.get(currentMacroPlatform(platform)) ?? parsed.fallback
154
+ }
155
+
156
+ export const dispatchMacro = async (
157
+ value: string,
158
+ handlers: {
159
+ runCommand: (cmd: string) => Promise<unknown>
160
+ keyMacro: (action: {
161
+ kind: "combo" | "key" | "text"
162
+ value: string
163
+ }) => Promise<void>
164
+ },
165
+ ): Promise<void> => {
166
+ const steps = parseMacro(value)
167
+ for (const step of steps) {
168
+ if (step.kind === "delay") {
169
+ await new Promise<void>((resolve) => setTimeout(resolve, step.ms))
170
+ continue
171
+ }
172
+ if (step.kind === "combo") {
173
+ await handlers.keyMacro({ kind: "combo", value: step.value })
174
+ continue
175
+ }
176
+ if (step.kind === "key") {
177
+ await handlers.keyMacro({ kind: "key", value: step.value })
178
+ continue
179
+ }
180
+ await handlers.keyMacro({ kind: "text", value: step.value })
181
+ }
182
+ }