@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.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/bin/_wrapper-shared.js +42 -0
- package/bin/dev.js +95 -0
- package/bin/sirenodeck.js +42 -0
- package/config/default-config.yml +117 -0
- package/config/starter-config.yml +54 -0
- package/dist/main.mjs +64702 -0
- package/package.json +140 -0
- package/src/action/executor.ts +156 -0
- package/src/action/index.ts +7 -0
- package/src/addon/api-types.ts +15 -0
- package/src/addon/api.ts +461 -0
- package/src/addon/check-runner.ts +84 -0
- package/src/addon/index.ts +5 -0
- package/src/addon/loader.ts +441 -0
- package/src/addon/registry.ts +230 -0
- package/src/addon/spec.ts +69 -0
- package/src/api/addon.ts +33 -0
- package/src/api/asset-url.ts +24 -0
- package/src/api/index.ts +50 -0
- package/src/api/protocol-internal.ts +656 -0
- package/src/api/protocol.ts +2 -0
- package/src/api/react/index.ts +11 -0
- package/src/api/react/registry.ts +91 -0
- package/src/api/react/use-addon-channel.ts +26 -0
- package/src/api/react/use-button-state.tsx +23 -0
- package/src/api/react/use-deck.ts +24 -0
- package/src/assets/logo.png +0 -0
- package/src/assets/logo72x72.png +0 -0
- package/src/assets/logoFull.png +0 -0
- package/src/builtin-addons/brightness/README.md +51 -0
- package/src/builtin-addons/brightness/buttons/brightness/backend.ts +13 -0
- package/src/builtin-addons/brightness/buttons/brightness/config.ts +10 -0
- package/src/builtin-addons/brightness/buttons/brightness/frontend.tsx +50 -0
- package/src/builtin-addons/brightness/domain/macos.ts +46 -0
- package/src/builtin-addons/brightness/index.d.ts +5 -0
- package/src/builtin-addons/brightness/index.ts +20 -0
- package/src/builtin-addons/brightness/poller.ts +27 -0
- package/src/builtin-addons/brightness/providers/darwin.ts +107 -0
- package/src/builtin-addons/brightness/providers/index.ts +81 -0
- package/src/builtin-addons/brightness/providers/linux.ts +108 -0
- package/src/builtin-addons/brightness/providers/windows.ts +77 -0
- package/src/builtin-addons/brightness/sirenodeck.json +6 -0
- package/src/builtin-addons/coding-agents/assets/claude-code.svg +1 -0
- package/src/builtin-addons/coding-agents/assets/opencode-dark-square.svg +1 -0
- package/src/builtin-addons/coding-agents/buttons/agent/backend.ts +82 -0
- package/src/builtin-addons/coding-agents/buttons/agent/config.ts +13 -0
- package/src/builtin-addons/coding-agents/buttons/agent/frontend.tsx +130 -0
- package/src/builtin-addons/coding-agents/buttons/agent/pages.tsx +150 -0
- package/src/builtin-addons/coding-agents/buttons/summary/backend.ts +48 -0
- package/src/builtin-addons/coding-agents/buttons/summary/config.ts +11 -0
- package/src/builtin-addons/coding-agents/buttons/summary/frontend.tsx +254 -0
- package/src/builtin-addons/coding-agents/decks/agents.ts +69 -0
- package/src/builtin-addons/coding-agents/global/backend.ts +402 -0
- package/src/builtin-addons/coding-agents/global-entry.ts +7 -0
- package/src/builtin-addons/coding-agents/hook/script.ts +123 -0
- package/src/builtin-addons/coding-agents/index.ts +15 -0
- package/src/builtin-addons/coding-agents/manifest.ts +115 -0
- package/src/builtin-addons/coding-agents/providers/claude-code.ts +470 -0
- package/src/builtin-addons/coding-agents/providers/claude-instances.ts +184 -0
- package/src/builtin-addons/coding-agents/providers/opencode-instances.ts +108 -0
- package/src/builtin-addons/coding-agents/providers/opencode.ts +636 -0
- package/src/builtin-addons/coding-agents/providers/registry.ts +120 -0
- package/src/builtin-addons/coding-agents/providers/spawn.ts +112 -0
- package/src/builtin-addons/coding-agents/shared/claude-hook-events.ts +55 -0
- package/src/builtin-addons/coding-agents/shared/claude-status.ts +236 -0
- package/src/builtin-addons/coding-agents/shared/live-count.ts +39 -0
- package/src/builtin-addons/coding-agents/shared/notifier.ts +58 -0
- package/src/builtin-addons/coding-agents/shared/opencode-status.ts +82 -0
- package/src/builtin-addons/coding-agents/shared/snapshot.ts +66 -0
- package/src/builtin-addons/coding-agents/shared/state.ts +72 -0
- package/src/builtin-addons/coding-agents/sirenodeck.json +6 -0
- package/src/builtin-addons/coding-agents/types/types.ts +33 -0
- package/src/builtin-addons/core/README.md +89 -0
- package/src/builtin-addons/core/buttons/action/backend.ts +7 -0
- package/src/builtin-addons/core/buttons/action/config.ts +13 -0
- package/src/builtin-addons/core/buttons/action/frontend.tsx +16 -0
- package/src/builtin-addons/core/buttons/change-deck/backend.ts +18 -0
- package/src/builtin-addons/core/buttons/change-deck/config.ts +15 -0
- package/src/builtin-addons/core/buttons/change-deck/frontend.tsx +18 -0
- package/src/builtin-addons/core/buttons/media-sample/backend.ts +8 -0
- package/src/builtin-addons/core/buttons/media-sample/config.ts +7 -0
- package/src/builtin-addons/core/buttons/media-sample/frontend.tsx +2 -0
- package/src/builtin-addons/core/buttons/page-nav/backend.ts +28 -0
- package/src/builtin-addons/core/buttons/page-nav/config.ts +9 -0
- package/src/builtin-addons/core/buttons/page-nav/frontend.tsx +68 -0
- package/src/builtin-addons/core/buttons/toggle/backend.ts +119 -0
- package/src/builtin-addons/core/buttons/toggle/config.ts +57 -0
- package/src/builtin-addons/core/buttons/toggle/frontend.tsx +57 -0
- package/src/builtin-addons/core/buttons/toggle/global-service.ts +174 -0
- package/src/builtin-addons/core/index.ts +120 -0
- package/src/builtin-addons/core/sirenodeck.json +6 -0
- package/src/builtin-addons/date-time/README.md +73 -0
- package/src/builtin-addons/date-time/buttons/analog-clock/backend.ts +10 -0
- package/src/builtin-addons/date-time/buttons/analog-clock/config.ts +4 -0
- package/src/builtin-addons/date-time/buttons/analog-clock/frontend.tsx +88 -0
- package/src/builtin-addons/date-time/buttons/custom/backend.ts +10 -0
- package/src/builtin-addons/date-time/buttons/custom/config.ts +9 -0
- package/src/builtin-addons/date-time/buttons/custom/frontend.tsx +26 -0
- package/src/builtin-addons/date-time/buttons/date/backend.ts +10 -0
- package/src/builtin-addons/date-time/buttons/date/config.ts +10 -0
- package/src/builtin-addons/date-time/buttons/date/frontend.tsx +42 -0
- package/src/builtin-addons/date-time/buttons/time/backend.ts +10 -0
- package/src/builtin-addons/date-time/buttons/time/config.ts +9 -0
- package/src/builtin-addons/date-time/buttons/time/frontend.tsx +29 -0
- package/src/builtin-addons/date-time/index.d.ts +5 -0
- package/src/builtin-addons/date-time/index.ts +30 -0
- package/src/builtin-addons/date-time/poller.ts +11 -0
- package/src/builtin-addons/date-time/shared/format-date.ts +36 -0
- package/src/builtin-addons/date-time/shared/format.ts +105 -0
- package/src/builtin-addons/date-time/shared/use-now.ts +10 -0
- package/src/builtin-addons/date-time/sirenodeck.json +6 -0
- package/src/builtin-addons/emoji-selector/README.md +45 -0
- package/src/builtin-addons/emoji-selector/assets/launcher.svg +10 -0
- package/src/builtin-addons/emoji-selector/assets/smileys.svg +8 -0
- package/src/builtin-addons/emoji-selector/buttons/category/backend.ts +14 -0
- package/src/builtin-addons/emoji-selector/buttons/category/config.ts +8 -0
- package/src/builtin-addons/emoji-selector/buttons/category/frontend.tsx +19 -0
- package/src/builtin-addons/emoji-selector/buttons/emoji/backend.ts +7 -0
- package/src/builtin-addons/emoji-selector/buttons/emoji/config.ts +9 -0
- package/src/builtin-addons/emoji-selector/buttons/emoji/frontend.tsx +11 -0
- package/src/builtin-addons/emoji-selector/buttons/launcher/backend.ts +13 -0
- package/src/builtin-addons/emoji-selector/buttons/launcher/config.ts +6 -0
- package/src/builtin-addons/emoji-selector/buttons/launcher/frontend.tsx +31 -0
- package/src/builtin-addons/emoji-selector/data/categories.ts +1084 -0
- package/src/builtin-addons/emoji-selector/decks/index.ts +137 -0
- package/src/builtin-addons/emoji-selector/index.d.ts +5 -0
- package/src/builtin-addons/emoji-selector/index.ts +29 -0
- package/src/builtin-addons/emoji-selector/sirenodeck.json +6 -0
- package/src/builtin-addons/emoji-selector/support.ts +49 -0
- package/src/builtin-addons/index.ts +13 -0
- package/src/builtin-addons/internal-settings/README.md +26 -0
- package/src/builtin-addons/internal-settings/backend.ts +58 -0
- package/src/builtin-addons/internal-settings/buttons/app-info/backend.ts +7 -0
- package/src/builtin-addons/internal-settings/buttons/app-info/config.ts +13 -0
- package/src/builtin-addons/internal-settings/buttons/app-info/frontend.tsx +18 -0
- package/src/builtin-addons/internal-settings/buttons/brightness/common/frontend.tsx +50 -0
- package/src/builtin-addons/internal-settings/buttons/brightness-down/backend.ts +16 -0
- package/src/builtin-addons/internal-settings/buttons/brightness-down/config.ts +6 -0
- package/src/builtin-addons/internal-settings/buttons/brightness-down/frontend.tsx +8 -0
- package/src/builtin-addons/internal-settings/buttons/brightness-up/backend.ts +16 -0
- package/src/builtin-addons/internal-settings/buttons/brightness-up/config.ts +6 -0
- package/src/builtin-addons/internal-settings/buttons/brightness-up/frontend.tsx +8 -0
- package/src/builtin-addons/internal-settings/decks/settings.ts +25 -0
- package/src/builtin-addons/internal-settings/index.d.ts +4 -0
- package/src/builtin-addons/internal-settings/index.ts +53 -0
- package/src/builtin-addons/internal-settings/logo72x72.png +0 -0
- package/src/builtin-addons/internal-settings/sirenodeck.json +6 -0
- package/src/builtin-addons/media/README.md +45 -0
- package/src/builtin-addons/media/backend.ts +143 -0
- package/src/builtin-addons/media/buttons/media-player/backend.ts +19 -0
- package/src/builtin-addons/media/buttons/media-player/components/MediaStatus.tsx +25 -0
- package/src/builtin-addons/media/buttons/media-player/components/MediaSurface.tsx +52 -0
- package/src/builtin-addons/media/buttons/media-player/components/ProgressBar.tsx +21 -0
- package/src/builtin-addons/media/buttons/media-player/components/status-meta.ts +36 -0
- package/src/builtin-addons/media/buttons/media-player/config.ts +4 -0
- package/src/builtin-addons/media/buttons/media-player/frontend.tsx +29 -0
- package/src/builtin-addons/media/buttons/volume/common/frontend.tsx +52 -0
- package/src/builtin-addons/media/buttons/volume/mute/backend.ts +13 -0
- package/src/builtin-addons/media/buttons/volume/mute/config.ts +4 -0
- package/src/builtin-addons/media/buttons/volume/mute/frontend.tsx +26 -0
- package/src/builtin-addons/media/buttons/volume/volume-down/backend.ts +14 -0
- package/src/builtin-addons/media/buttons/volume/volume-down/config.ts +6 -0
- package/src/builtin-addons/media/buttons/volume/volume-down/frontend.tsx +10 -0
- package/src/builtin-addons/media/buttons/volume/volume-up/backend.ts +14 -0
- package/src/builtin-addons/media/buttons/volume/volume-up/config.ts +6 -0
- package/src/builtin-addons/media/buttons/volume/volume-up/frontend.tsx +8 -0
- package/src/builtin-addons/media/checks.ts +104 -0
- package/src/builtin-addons/media/executor.ts +36 -0
- package/src/builtin-addons/media/index.d.ts +5 -0
- package/src/builtin-addons/media/index.ts +53 -0
- package/src/builtin-addons/media/progress.ts +16 -0
- package/src/builtin-addons/media/providers/darwin.ts +391 -0
- package/src/builtin-addons/media/providers/index.ts +27 -0
- package/src/builtin-addons/media/providers/linux.ts +196 -0
- package/src/builtin-addons/media/providers/types.ts +48 -0
- package/src/builtin-addons/media/providers/windows.ts +121 -0
- package/src/builtin-addons/media/sirenodeck.json +6 -0
- package/src/builtin-addons/media/state.ts +19 -0
- package/src/builtin-addons/register-builtins.ts +65 -0
- package/src/builtin-addons/session/README.md +14 -0
- package/src/builtin-addons/session/buttons/session-info/backend.ts +8 -0
- package/src/builtin-addons/session/buttons/session-info/config.ts +4 -0
- package/src/builtin-addons/session/buttons/session-info/frontend.tsx +2 -0
- package/src/builtin-addons/session/buttons/time/backend.ts +7 -0
- package/src/builtin-addons/session/buttons/time/config.ts +6 -0
- package/src/builtin-addons/session/buttons/time/frontend.tsx +2 -0
- package/src/builtin-addons/session/index.d.ts +5 -0
- package/src/builtin-addons/session/index.ts +18 -0
- package/src/builtin-addons/session/sirenodeck.json +6 -0
- package/src/builtin-addons/system-status/README.md +169 -0
- package/src/builtin-addons/system-status/buttons/_shared.ts +131 -0
- package/src/builtin-addons/system-status/buttons/system-status/frontend.tsx +224 -0
- package/src/builtin-addons/system-status/buttons/system-status/schemas.ts +67 -0
- package/src/builtin-addons/system-status/domain/catalog.ts +53 -0
- package/src/builtin-addons/system-status/domain/chart-sampler.ts +58 -0
- package/src/builtin-addons/system-status/domain/display-metrics.ts +128 -0
- package/src/builtin-addons/system-status/domain/index.ts +10 -0
- package/src/builtin-addons/system-status/domain/live-metrics.ts +1021 -0
- package/src/builtin-addons/system-status/domain/metric-ids.ts +0 -0
- package/src/builtin-addons/system-status/index.ts +16 -0
- package/src/builtin-addons/system-status/manifest.ts +105 -0
- package/src/builtin-addons/system-status/shared/metrics-catalog.ts +316 -0
- package/src/builtin-addons/system-status/sirenodeck.json +6 -0
- package/src/builtin-addons/test-buildin/decks/action-buttons-test.ts +56 -0
- package/src/builtin-addons/test-buildin/index.d.ts +5 -0
- package/src/builtin-addons/test-buildin/index.ts +16 -0
- package/src/builtin-addons/value-display/README.md +59 -0
- package/src/builtin-addons/value-display/backend.ts +86 -0
- package/src/builtin-addons/value-display/buttons/value-display/backend.ts +17 -0
- package/src/builtin-addons/value-display/buttons/value-display/config.ts +36 -0
- package/src/builtin-addons/value-display/buttons/value-display/frontend.tsx +54 -0
- package/src/builtin-addons/value-display/index.d.ts +5 -0
- package/src/builtin-addons/value-display/index.ts +23 -0
- package/src/builtin-addons/value-display/sirenodeck.json +6 -0
- package/src/builtin-addons/weather/README.md +46 -0
- package/src/builtin-addons/weather/backend.ts +121 -0
- package/src/builtin-addons/weather/buttons/weather/backend.ts +27 -0
- package/src/builtin-addons/weather/buttons/weather/config.ts +29 -0
- package/src/builtin-addons/weather/buttons/weather/frontend.tsx +63 -0
- package/src/builtin-addons/weather/buttons/weather/icons.tsx +88 -0
- package/src/builtin-addons/weather/buttons/weather/pages.tsx +109 -0
- package/src/builtin-addons/weather/domain/codes.ts +35 -0
- package/src/builtin-addons/weather/domain/fetch.ts +47 -0
- package/src/builtin-addons/weather/index.d.ts +5 -0
- package/src/builtin-addons/weather/index.ts +23 -0
- package/src/builtin-addons/weather/poller.ts +70 -0
- package/src/builtin-addons/weather/provider/city-key.ts +9 -0
- package/src/builtin-addons/weather/provider/codes.ts +35 -0
- package/src/builtin-addons/weather/provider/fetch.ts +97 -0
- package/src/builtin-addons/weather/provider/geocode.ts +67 -0
- package/src/builtin-addons/weather/provider/types.ts +42 -0
- package/src/builtin-addons/weather/sirenodeck.json +6 -0
- package/src/cli/coding-agents-onboarding.ts +434 -0
- package/src/cli/commands/addon-decks.ts +441 -0
- package/src/cli/commands/addon-registry.ts +639 -0
- package/src/cli/commands/emulator-mode.ts +289 -0
- package/src/cli/commands/install.ts +128 -0
- package/src/cli/commands/logs.ts +74 -0
- package/src/cli/commands/network-bind.ts +111 -0
- package/src/cli/commands/pipeline/helpers.ts +75 -0
- package/src/cli/commands/pipeline/preflight.ts +20 -0
- package/src/cli/commands/port-identity.ts +152 -0
- package/src/cli/commands/reload.ts +37 -0
- package/src/cli/commands/restart.ts +139 -0
- package/src/cli/commands/run.ts +2270 -0
- package/src/cli/commands/service/install.ts +121 -0
- package/src/cli/commands/service/render-template.ts +158 -0
- package/src/cli/commands/service-manager.ts +184 -0
- package/src/cli/commands/spawn-daemon.ts +251 -0
- package/src/cli/commands/start.ts +1061 -0
- package/src/cli/commands/status.ts +110 -0
- package/src/cli/commands/stop.ts +121 -0
- package/src/cli/commands/subprocess-supervisor.ts +203 -0
- package/src/cli/commands/system-requirements.ts +699 -0
- package/src/cli/cwd.ts +28 -0
- package/src/cli/first-run.ts +149 -0
- package/src/cli/http-server.ts +244 -0
- package/src/cli/index.ts +355 -0
- package/src/cli/install-root.ts +26 -0
- package/src/cli/main.ts +194 -0
- package/src/cli/package-manager.ts +175 -0
- package/src/cli/probe-deps.ts +45 -0
- package/src/cli/prompt.ts +22 -0
- package/src/cli/startup-display.ts +452 -0
- package/src/config/builtin-icons.ts +57 -0
- package/src/config/config-diff.ts +54 -0
- package/src/config/discovery.ts +64 -0
- package/src/config/icon-resolver.ts +90 -0
- package/src/config/include-resolver.ts +202 -0
- package/src/config/index.ts +9 -0
- package/src/config/loader.ts +187 -0
- package/src/config/mutation.ts +514 -0
- package/src/config/reference-expander.ts +84 -0
- package/src/config/schemas.ts +223 -0
- package/src/config/validation.ts +254 -0
- package/src/core/asset-id.ts +21 -0
- package/src/core/gesture-state.ts +344 -0
- package/src/core/icon-asset-registry.ts +127 -0
- package/src/core/icon-source.ts +86 -0
- package/src/core/index.ts +30 -0
- package/src/core/mime.ts +16 -0
- package/src/core/pagination.ts +90 -0
- package/src/core/pub-sub.ts +126 -0
- package/src/core/settings.ts +153 -0
- package/src/core/store.ts +88 -0
- package/src/core/watcher.ts +73 -0
- package/src/deck/addon-handler-bridge.ts +516 -0
- package/src/deck/deck-config.ts +271 -0
- package/src/deck/editor-surfaces.ts +87 -0
- package/src/deck/host-context.ts +18 -0
- package/src/deck/index.ts +102 -0
- package/src/deck/macro-parse.ts +182 -0
- package/src/deck/methods.ts +348 -0
- package/src/deck/paginate-deck.ts +98 -0
- package/src/deck/position-buttons.ts +57 -0
- package/src/deck/runtime/index.ts +5 -0
- package/src/deck/runtime/runtime.ts +1060 -0
- package/src/deck/runtime-subscriptions.ts +45 -0
- package/src/deck/system-back-injection.ts +62 -0
- package/src/deck/system-buttons/registry.tsx +97 -0
- package/src/deck/system-buttons/types.ts +14 -0
- package/src/device/black-frame.ts +73 -0
- package/src/device/index.ts +13 -0
- package/src/device/linux-udev.ts +36 -0
- package/src/device/models.ts +89 -0
- package/src/device/reconnecting.ts +193 -0
- package/src/device/registry.ts +38 -0
- package/src/device/stream-deck.ts +155 -0
- package/src/index.ts +74 -0
- package/src/outputClient/emulator.ts +357 -0
- package/src/outputClient/index.ts +26 -0
- package/src/outputClient/open-browser.ts +26 -0
- package/src/outputClient/real.ts +393 -0
- package/src/outputClient/types.ts +83 -0
- package/src/render/browser-renderer.ts +240 -0
- package/src/render/buffer-hash.ts +20 -0
- package/src/render/editor-handler.ts +197 -0
- package/src/render/emulator-server.ts +128 -0
- package/src/render/icon-source-resolver.ts +69 -0
- package/src/render/index.ts +16 -0
- package/src/render/protocol.ts +61 -0
- package/src/render/push-raw-image.ts +100 -0
- package/src/render/screenshot-cadence.ts +87 -0
- package/src/render/state-publisher.ts +110 -0
- package/src/render/vite-server.ts +138 -0
- package/src/render/ws-bridge.ts +315 -0
- package/src/system/device-selection.ts +80 -0
- package/src/system/glob-match.ts +74 -0
- package/src/system/providers/active-app/darwin.ts +117 -0
- package/src/system/providers/active-app/linux.ts +245 -0
- package/src/system/providers/active-app/wayland-gnome.ts +303 -0
- package/src/system/providers/active-app/windows.ts +94 -0
- package/src/system/providers/active-app.ts +97 -0
- package/src/system/providers/clipboard/darwin.ts +65 -0
- package/src/system/providers/clipboard/linux.ts +163 -0
- package/src/system/providers/clipboard/windows.ts +94 -0
- package/src/system/providers/clipboard.ts +84 -0
- package/src/system/providers/error.ts +16 -0
- package/src/system/providers/key-macro/darwin.ts +221 -0
- package/src/system/providers/key-macro/linux.ts +651 -0
- package/src/system/providers/key-macro/parser.ts +215 -0
- package/src/system/providers/key-macro/windows.ts +476 -0
- package/src/system/providers/key-macro.ts +79 -0
- package/src/system/providers/notification/darwin.ts +36 -0
- package/src/system/providers/notification/linux.ts +115 -0
- package/src/system/providers/notification/windows.ts +72 -0
- package/src/system/providers/notification.ts +75 -0
- package/src/system/providers/session/darwin.ts +82 -0
- package/src/system/providers/session/linux.ts +175 -0
- package/src/system/providers/session/windows.ts +73 -0
- package/src/system/providers/session.ts +89 -0
- package/src/system/providers/shared.ts +65 -0
- package/src/system/requirements.ts +235 -0
- package/src/system/setup-wizard/config-seed.ts +30 -0
- package/src/system/setup-wizard/format.ts +275 -0
- package/src/system/setup-wizard/index.ts +45 -0
- package/src/system/setup-wizard/open-settings.ts +26 -0
- package/src/system/setup-wizard/plan.ts +230 -0
- package/src/system/setup-wizard/probe-cache.ts +34 -0
- package/src/system/setup-wizard/probe.ts +486 -0
- package/src/system/setup-wizard/runtime-features.ts +85 -0
- package/src/system/setup-wizard/sudo.ts +178 -0
- package/src/system/setup-wizard/types.ts +133 -0
- package/src/system/virtual-stream-deck.ts +67 -0
- package/src/themes/css.ts +210 -0
- package/src/themes/default/assets/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/src/themes/default/assets/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Bold.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-BoldItalic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-ExtraLight.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-ExtraLightItalic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Italic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Light.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-LightItalic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Medium.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-MediumItalic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Regular.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-SemiBold.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-SemiBoldItalic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-Thin.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/IBMPlexMono-ThinItalic.ttf +0 -0
- package/src/themes/default/assets/IBM_Plex_Mono/OFL.txt +93 -0
- package/src/themes/default/assets/OFL.txt +93 -0
- package/src/themes/default/assets/README.txt +106 -0
- package/src/themes/default/assets/static/IBMPlexSans-Bold.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-BoldItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-ExtraLight.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-ExtraLightItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-Italic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-Light.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-LightItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-Medium.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-MediumItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-Regular.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-SemiBold.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-SemiBoldItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-Thin.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans-ThinItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-Bold.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-BoldItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-ExtraLight.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-ExtraLightItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-Italic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-Light.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-LightItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-Medium.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-MediumItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-Regular.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-SemiBold.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-SemiBoldItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-Thin.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_Condensed-ThinItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Bold.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-BoldItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-ExtraLight.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-ExtraLightItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Italic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Light.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-LightItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Medium.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-MediumItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Regular.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-SemiBold.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-Thin.ttf +0 -0
- package/src/themes/default/assets/static/IBMPlexSans_SemiCondensed-ThinItalic.ttf +0 -0
- package/src/themes/default/components.css +81 -0
- package/src/themes/default/sirenodeck.json +170 -0
- package/src/themes/index.ts +14 -0
- package/src/themes/light/assets/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/src/themes/light/assets/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
- package/src/themes/light/assets/IBM_Plex_Mono/IBMPlexMono-Bold.ttf +0 -0
- package/src/themes/light/assets/IBM_Plex_Mono/IBMPlexMono-Medium.ttf +0 -0
- package/src/themes/light/assets/IBM_Plex_Mono/IBMPlexMono-Regular.ttf +0 -0
- package/src/themes/light/assets/IBM_Plex_Mono/OFL.txt +93 -0
- package/src/themes/light/assets/OFL.txt +93 -0
- package/src/themes/light/assets/README.txt +106 -0
- package/src/themes/light/assets/static/IBMPlexSans-Light.ttf +0 -0
- package/src/themes/light/assets/static/IBMPlexSans-LightItalic.ttf +0 -0
- package/src/themes/light/assets/static/IBMPlexSans-Thin.ttf +0 -0
- package/src/themes/light/components.css +70 -0
- package/src/themes/light/sirenodeck.json +170 -0
- package/src/themes/loader.ts +343 -0
- package/src/themes/manifest.ts +164 -0
- package/src/themes/use-resolved-theme.tsx +32 -0
- package/src/ui/ButtonFrame.tsx +230 -0
- package/src/ui/contexts/AssetCacheContext.tsx +43 -0
- package/src/ui/index.ts +20 -0
- package/src/ui/primitives/Chip.tsx +53 -0
- package/src/ui/primitives/Icon.tsx +209 -0
- package/src/ui/primitives/Label.tsx +82 -0
- package/src/ui/primitives/ProgressBar.tsx +38 -0
- package/src/ui/primitives/TapIndicator.tsx +67 -0
- package/src/ui/primitives/Text.tsx +810 -0
- package/src/ui/primitives/index.ts +6 -0
- package/src/ui/surfaces/BarsSurface.tsx +211 -0
- package/src/ui/surfaces/IconLabelProgressSurface.tsx +133 -0
- package/src/ui/surfaces/IconLabelSurface.tsx +59 -0
- package/src/ui/surfaces/LabelValueListSurface.tsx +202 -0
- package/src/ui/surfaces/PaginatedSurface.tsx +164 -0
- package/src/ui/surfaces/SplitActionSurface.tsx +98 -0
- package/src/ui/surfaces/TemporaryErrorSurface.tsx +68 -0
- package/src/ui/surfaces/ValueChart.tsx +218 -0
- package/src/ui/surfaces/index.ts +32 -0
- package/src/ui/surfaces/paginated-schema.ts +22 -0
- package/src/ui/theme-presentation-builder.ts +184 -0
- package/src/ui/theme-presentation.tsx +146 -0
- package/src/ui/utils/cn.ts +12 -0
- package/src/util/cache-paths.ts +38 -0
- package/src/util/config-diff.ts +16 -0
- package/src/util/daemon-control.ts +85 -0
- package/src/util/daemon.ts +575 -0
- package/src/util/device-config.ts +56 -0
- package/src/util/errors.ts +13 -0
- package/src/util/log-reader.ts +114 -0
- package/src/util/log-tail.ts +103 -0
- package/src/util/logger.ts +417 -0
- package/src/util/process-title.ts +79 -0
- package/src/util/single-instance.ts +202 -0
- package/src/version.ts +10 -0
- package/src/vite/index.ts +6 -0
- package/src/vite/virtual-modules.ts +631 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Unsubscribe } from "@/api/addon"
|
|
2
|
+
|
|
3
|
+
export type ChannelPayload = unknown
|
|
4
|
+
|
|
5
|
+
type Listener = (payload: ChannelPayload) => void
|
|
6
|
+
type AnnounceSubscribe = (channels: string[]) => void
|
|
7
|
+
|
|
8
|
+
export class ChannelRegistry {
|
|
9
|
+
private static _instance: ChannelRegistry | null = null
|
|
10
|
+
private static _announceSubscribe: AnnounceSubscribe | null = null
|
|
11
|
+
private readonly lastPayloads = new Map<string, ChannelPayload>()
|
|
12
|
+
private readonly listeners = new Map<string, Set<Listener>>()
|
|
13
|
+
private readonly listenerCounts = new Map<string, number>()
|
|
14
|
+
private pendingChannels: string[] = []
|
|
15
|
+
private flushScheduled = false
|
|
16
|
+
|
|
17
|
+
static instance(): ChannelRegistry {
|
|
18
|
+
if (ChannelRegistry._instance === null) {
|
|
19
|
+
ChannelRegistry._instance = new ChannelRegistry()
|
|
20
|
+
}
|
|
21
|
+
return ChannelRegistry._instance
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static resetForTests(): void {
|
|
25
|
+
ChannelRegistry._instance = null
|
|
26
|
+
ChannelRegistry._announceSubscribe = null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static setAnnounceSubscribe(cb: AnnounceSubscribe | null): void {
|
|
30
|
+
ChannelRegistry._announceSubscribe = cb
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
publish<T extends ChannelPayload>(channel: string, payload: T): void {
|
|
34
|
+
this.lastPayloads.set(channel, payload)
|
|
35
|
+
const set = this.listeners.get(channel)
|
|
36
|
+
if (set !== undefined) for (const l of set) l(payload)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
subscribe<T extends ChannelPayload>(
|
|
40
|
+
channel: string,
|
|
41
|
+
cb: (payload: T) => void,
|
|
42
|
+
): Unsubscribe {
|
|
43
|
+
let set = this.listeners.get(channel)
|
|
44
|
+
if (set === undefined) {
|
|
45
|
+
set = new Set()
|
|
46
|
+
this.listeners.set(channel, set)
|
|
47
|
+
}
|
|
48
|
+
const listener = cb as Listener
|
|
49
|
+
set.add(listener)
|
|
50
|
+
|
|
51
|
+
const prevCount = this.listenerCounts.get(channel) ?? 0
|
|
52
|
+
this.listenerCounts.set(channel, prevCount + 1)
|
|
53
|
+
if (prevCount === 0) {
|
|
54
|
+
this.pendingChannels.push(channel)
|
|
55
|
+
if (!this.flushScheduled) {
|
|
56
|
+
this.flushScheduled = true
|
|
57
|
+
queueMicrotask(() => this.flushPendingSubscriptions())
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return () => {
|
|
62
|
+
set?.delete(listener)
|
|
63
|
+
const count = this.listenerCounts.get(channel) ?? 0
|
|
64
|
+
if (count <= 1) {
|
|
65
|
+
this.listenerCounts.delete(channel)
|
|
66
|
+
} else {
|
|
67
|
+
this.listenerCounts.set(channel, count - 1)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private flushPendingSubscriptions(): void {
|
|
73
|
+
this.flushScheduled = false
|
|
74
|
+
if (this.pendingChannels.length === 0) return
|
|
75
|
+
const channels = [...new Set(this.pendingChannels)]
|
|
76
|
+
this.pendingChannels = []
|
|
77
|
+
ChannelRegistry._announceSubscribe?.(channels)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
last<T extends ChannelPayload>(channel: string): T | undefined {
|
|
81
|
+
return this.lastPayloads.get(channel) as T | undefined
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
clear(): void {
|
|
85
|
+
this.lastPayloads.clear()
|
|
86
|
+
this.listeners.clear()
|
|
87
|
+
this.listenerCounts.clear()
|
|
88
|
+
this.pendingChannels = []
|
|
89
|
+
this.flushScheduled = false
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
|
|
3
|
+
import { ChannelRegistry } from "./registry"
|
|
4
|
+
import type { ChannelPayload } from "@/api/addon"
|
|
5
|
+
|
|
6
|
+
export interface UseAddonChannelReturn<T = unknown> {
|
|
7
|
+
data: T | undefined
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const useAddonChannel = <T = unknown>(
|
|
11
|
+
channel: string,
|
|
12
|
+
): UseAddonChannelReturn<T> => {
|
|
13
|
+
const [data, setData] = useState<T | undefined>(() =>
|
|
14
|
+
ChannelRegistry.instance().last<T>(channel),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
return ChannelRegistry.instance().subscribe<T>(channel, (payload) => {
|
|
19
|
+
setData(payload)
|
|
20
|
+
})
|
|
21
|
+
}, [channel])
|
|
22
|
+
|
|
23
|
+
return { data }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type { ChannelRegistry, ChannelPayload }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useAddonChannel,
|
|
3
|
+
type ChannelRegistry,
|
|
4
|
+
type ChannelPayload,
|
|
5
|
+
} from "./use-addon-channel"
|
|
6
|
+
|
|
7
|
+
export { useAddonChannel, type ChannelRegistry, type ChannelPayload }
|
|
8
|
+
|
|
9
|
+
export interface UseButtonStateReturn<T = unknown> {
|
|
10
|
+
readonly state: T | undefined
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const useButtonState = <T = unknown,>(
|
|
14
|
+
addonName: string,
|
|
15
|
+
buttonType: string,
|
|
16
|
+
buttonId: string,
|
|
17
|
+
): UseButtonStateReturn<T> => {
|
|
18
|
+
const channel = `${addonName}:${buttonType}:${buttonId}`
|
|
19
|
+
const { data } = useAddonChannel<T>(channel)
|
|
20
|
+
return { state: data }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const NullButton = (): null => null
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
|
|
3
|
+
import { ChannelRegistry } from "./registry"
|
|
4
|
+
|
|
5
|
+
export interface UseDeckReturn {
|
|
6
|
+
activeDeckId: string | null
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const useDeck = (): UseDeckReturn => {
|
|
10
|
+
const [activeDeckId, setActiveDeckId] = useState<string | null>(
|
|
11
|
+
() => ChannelRegistry.instance().last<string>("runtime:activeDeck") ?? null,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
return ChannelRegistry.instance().subscribe<{ deckId: string }>(
|
|
16
|
+
"runtime:activeDeck",
|
|
17
|
+
(payload) => {
|
|
18
|
+
setActiveDeckId(payload.deckId)
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
}, [])
|
|
22
|
+
|
|
23
|
+
return { activeDeckId }
|
|
24
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# brightness
|
|
2
|
+
|
|
3
|
+
Single button that adjusts screen brightness. Tap = action (up/down/set). The button shows the current brightness as a bar.
|
|
4
|
+
|
|
5
|
+
Uses the OS provider from `packages/cli/src/system/providers/`:
|
|
6
|
+
|
|
7
|
+
- Linux: `xrandr` / `brightnessctl` (whichever is available)
|
|
8
|
+
- macOS: `osascript`
|
|
9
|
+
- Windows: PowerShell + WMI
|
|
10
|
+
|
|
11
|
+
## Buttons
|
|
12
|
+
|
|
13
|
+
| Type | Description |
|
|
14
|
+
| ----------------------- | ------------------------------------------------ |
|
|
15
|
+
| `brightness:brightness` | Single button: shows + adjusts screen brightness |
|
|
16
|
+
|
|
17
|
+
## Config
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
- position: 5
|
|
21
|
+
type: brightness:brightness
|
|
22
|
+
config:
|
|
23
|
+
action: up # "up" (default), "down", or "set"
|
|
24
|
+
value: 75 # required for "set" (0-100); ignored for up/down
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Gesture semantics
|
|
28
|
+
|
|
29
|
+
- **Tap** on a `brightness:brightness` button → executes the configured `action`.
|
|
30
|
+
- **Hold** on a `brightness:brightness` button → toggles between `up` and `down` for fine-grained adjustment.
|
|
31
|
+
|
|
32
|
+
## Example
|
|
33
|
+
|
|
34
|
+
In your `settings` deck (auto-generated by `internal-settings`):
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
decks:
|
|
38
|
+
settings:
|
|
39
|
+
name: Settings
|
|
40
|
+
buttons:
|
|
41
|
+
- position: 0
|
|
42
|
+
type: brightness:brightness
|
|
43
|
+
config: { action: up }
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Run `xrandr --output eDP-1 --brightness 0.75` (Linux) to verify the action works on your system.
|
|
47
|
+
|
|
48
|
+
## See also
|
|
49
|
+
|
|
50
|
+
- [system-status](../system-status/README.md) — same polling pattern; brightness is just a one-button metric
|
|
51
|
+
- [OS providers](../../../../system/providers/README.md) — brightness provider per OS
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AddonButtonTypeService } from "@/addon/api"
|
|
2
|
+
|
|
3
|
+
import { buildMacOSCommand, formatCommand, isMacOS } from "../../domain/macos"
|
|
4
|
+
import { configSchema, type ConfigSchema } from "./config"
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
configSchema,
|
|
8
|
+
defaultRenderIntervalMs: 2000,
|
|
9
|
+
onTap: ({ config, executor }) => {
|
|
10
|
+
if (!isMacOS(process.platform)) return
|
|
11
|
+
void executor.run(formatCommand(buildMacOSCommand(config))).catch(() => {})
|
|
12
|
+
},
|
|
13
|
+
} satisfies AddonButtonTypeService<ConfigSchema>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
export const configSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
action: z.enum(["up", "down", "set"]).optional().default("up"),
|
|
6
|
+
value: z.number().int().min(0).max(100).optional(),
|
|
7
|
+
})
|
|
8
|
+
.strict()
|
|
9
|
+
|
|
10
|
+
export type ConfigSchema = z.infer<typeof configSchema>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Text } from "@/ui/index"
|
|
2
|
+
import { useAddonChannel } from "@/api/react"
|
|
3
|
+
import type { AddonFrontendButton } from "@/addon/api"
|
|
4
|
+
|
|
5
|
+
import type { ConfigSchema } from "./config"
|
|
6
|
+
|
|
7
|
+
interface BrightnessState {
|
|
8
|
+
readonly value: number
|
|
9
|
+
readonly max: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const BrightnessButtonFrontend: AddonFrontendButton<ConfigSchema> = ({
|
|
13
|
+
config,
|
|
14
|
+
}) => {
|
|
15
|
+
const { action } = config ?? {}
|
|
16
|
+
const { data } = useAddonChannel<BrightnessState>("brightness:current")
|
|
17
|
+
if (data === undefined) {
|
|
18
|
+
return (
|
|
19
|
+
<Text
|
|
20
|
+
size="xs"
|
|
21
|
+
tone="muted"
|
|
22
|
+
typography="mono"
|
|
23
|
+
className="flex h-full w-full items-center justify-center"
|
|
24
|
+
text="—"
|
|
25
|
+
/>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
const pct = Math.max(0, Math.min(100, (data.value / (data.max || 100)) * 100))
|
|
29
|
+
return (
|
|
30
|
+
<span className="flex h-full w-full flex-col items-stretch justify-center gap-1 p-2">
|
|
31
|
+
<span className="flex items-baseline justify-between">
|
|
32
|
+
<Text size="xs" tone="muted" fit="ellipsis" text="Brightness" />
|
|
33
|
+
<Text size="xs" tone="fg" text={`${pct.toFixed(0)}%`} />
|
|
34
|
+
</span>
|
|
35
|
+
<span className="block h-1.5 w-full overflow-hidden rounded bg-bar">
|
|
36
|
+
<span className="block h-full bg-accent" style={{ width: `${pct}%` }} />
|
|
37
|
+
</span>
|
|
38
|
+
<Text
|
|
39
|
+
size="xs"
|
|
40
|
+
tone="muted"
|
|
41
|
+
className="text-center"
|
|
42
|
+
typography="aux"
|
|
43
|
+
text={`Tap: ${action ?? "up"}`}
|
|
44
|
+
/>
|
|
45
|
+
</span>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default BrightnessButtonFrontend
|
|
50
|
+
export { BrightnessButtonFrontend }
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ConfigSchema as BrightnessButtonConfig } from "../buttons/brightness/config"
|
|
2
|
+
|
|
3
|
+
const escape = (s: string): string => `'${s.replaceAll("'", "'\\''")}'`
|
|
4
|
+
|
|
5
|
+
export const isMacOS = (platform: NodeJS.Platform): boolean =>
|
|
6
|
+
platform === "darwin"
|
|
7
|
+
|
|
8
|
+
export const setBrightnessMacOS = async (
|
|
9
|
+
config: BrightnessButtonConfig,
|
|
10
|
+
exec: (
|
|
11
|
+
cmd: string,
|
|
12
|
+
args: string[],
|
|
13
|
+
) => Promise<{ exitCode: number; stderr: string }>,
|
|
14
|
+
): Promise<void> => {
|
|
15
|
+
if (config.action === "set" && config.value !== undefined) {
|
|
16
|
+
const script = `tell application "System Events" to set brightness of (first item of (get displays)) to ${config.value / 100}`
|
|
17
|
+
await exec("osascript", ["-e", script])
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
if (config.action === "down") {
|
|
21
|
+
await exec("osascript", [
|
|
22
|
+
"-e",
|
|
23
|
+
`tell application "System Events" to key code 145`,
|
|
24
|
+
])
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
await exec("osascript", [
|
|
28
|
+
"-e",
|
|
29
|
+
`tell application "System Events" to key code 144`,
|
|
30
|
+
])
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const buildMacOSCommand = (
|
|
34
|
+
config: BrightnessButtonConfig,
|
|
35
|
+
): readonly string[] => {
|
|
36
|
+
if (config.action === "set" && config.value !== undefined) {
|
|
37
|
+
return ["osascript", "-e", `set brightness to ${config.value / 100}`]
|
|
38
|
+
}
|
|
39
|
+
if (config.action === "down") {
|
|
40
|
+
return ["osascript", "-e", `key code 145`]
|
|
41
|
+
}
|
|
42
|
+
return ["osascript", "-e", `key code 144`]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const formatCommand = (cmd: readonly string[]): string =>
|
|
46
|
+
cmd.map(escape).join(" ")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AddonManifestV1 } from "@/addon/api"
|
|
2
|
+
|
|
3
|
+
import brightnessBackend from "./buttons/brightness/backend"
|
|
4
|
+
import brightnessFrontend from "./buttons/brightness/frontend"
|
|
5
|
+
|
|
6
|
+
export const manifest: AddonManifestV1 = {
|
|
7
|
+
apiVersion: 1,
|
|
8
|
+
name: "brightness",
|
|
9
|
+
buttonTypes: {
|
|
10
|
+
"brightness:brightness": {
|
|
11
|
+
frontend: brightnessFrontend,
|
|
12
|
+
service: { ...brightnessBackend, gestureHandlers: ["tap"] as const },
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
publishIntervalMs: 2000,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const brightnessAddon = manifest
|
|
19
|
+
export default manifest
|
|
20
|
+
export { brightnessBackend, brightnessFrontend }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AddonPoller } from "@/addon/api-types"
|
|
2
|
+
|
|
3
|
+
import type { BrightnessProvider } from "./providers"
|
|
4
|
+
|
|
5
|
+
export interface BrightnessPollerDeps {
|
|
6
|
+
readonly brightnessProvider: BrightnessProvider | null
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const createPoller = (deps: BrightnessPollerDeps): AddonPoller => ({
|
|
10
|
+
channels: [
|
|
11
|
+
{
|
|
12
|
+
channel: "brightness:current",
|
|
13
|
+
intervalMs: 2_000,
|
|
14
|
+
poll: async () => {
|
|
15
|
+
if (deps.brightnessProvider === null) {
|
|
16
|
+
return { value: 0, max: 100 }
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const reading = await deps.brightnessProvider.getCurrent()
|
|
20
|
+
return { value: reading.value, max: reading.max }
|
|
21
|
+
} catch {
|
|
22
|
+
return { value: 0, max: 100 }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
})
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type pino from "pino"
|
|
2
|
+
|
|
3
|
+
import { type CommandExecutor } from "@/system/providers/shared"
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
createNullBrightnessProvider,
|
|
7
|
+
type BrightnessProvider,
|
|
8
|
+
type BrightnessReading,
|
|
9
|
+
} from "./index"
|
|
10
|
+
|
|
11
|
+
export interface CreateDarwinBrightnessProviderOptions {
|
|
12
|
+
readonly executor: CommandExecutor
|
|
13
|
+
readonly logger: pino.Logger
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ponytail: this provider used to shell out to
|
|
17
|
+
// `tell application "System Events" to get brightness of (every item of
|
|
18
|
+
// displays)`. System Events has no `displays` element, so every call failed
|
|
19
|
+
// with "The variable displays is not defined (-2753)" and brightness has never
|
|
20
|
+
// worked on macOS. There is no public CLI or ioreg node for display brightness
|
|
21
|
+
// on Apple Silicon (it moved into the private DisplayServices framework), so
|
|
22
|
+
// the honest options are the `brightness` Homebrew binary or nothing.
|
|
23
|
+
//
|
|
24
|
+
// `brightness -l` prints one "display N: brightness 0.550000" line per display;
|
|
25
|
+
// `brightness <0..1>` sets every display. Values are 0..1 on the wire and
|
|
26
|
+
// 0..100 across the BrightnessProvider interface.
|
|
27
|
+
const BRIGHTNESS_BIN = "brightness"
|
|
28
|
+
const INSTALL_HINT = "install it with `brew install brightness`"
|
|
29
|
+
|
|
30
|
+
const BRIGHTNESS_LINE = /display\s+\d+:\s+brightness\s+([0-9]*\.?[0-9]+)/i
|
|
31
|
+
|
|
32
|
+
export const parseBrightnessList = (
|
|
33
|
+
stdout: string,
|
|
34
|
+
): BrightnessReading | null => {
|
|
35
|
+
const match = BRIGHTNESS_LINE.exec(stdout)
|
|
36
|
+
if (match?.[1] === undefined) return null
|
|
37
|
+
const fraction = Number.parseFloat(match[1])
|
|
38
|
+
if (!Number.isFinite(fraction)) return null
|
|
39
|
+
const clamped = Math.max(0, Math.min(1, fraction))
|
|
40
|
+
return { value: Math.round(clamped * 100), max: 100 }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const createDarwinBrightnessProvider = (
|
|
44
|
+
options: CreateDarwinBrightnessProviderOptions,
|
|
45
|
+
): BrightnessProvider => {
|
|
46
|
+
const { executor, logger } = options
|
|
47
|
+
const nullProvider = createNullBrightnessProvider(logger)
|
|
48
|
+
let disposed = false
|
|
49
|
+
// Warn once, not on every poll tick.
|
|
50
|
+
let warnedMissing = false
|
|
51
|
+
|
|
52
|
+
const warnMissing = (detail: string): void => {
|
|
53
|
+
if (warnedMissing) return
|
|
54
|
+
warnedMissing = true
|
|
55
|
+
logger.warn(
|
|
56
|
+
{ bin: BRIGHTNESS_BIN, detail },
|
|
57
|
+
`brightness: '${BRIGHTNESS_BIN}' unavailable — ${INSTALL_HINT}`,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const stop = async (): Promise<void> => {
|
|
62
|
+
disposed = true
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const getCurrent = async (): Promise<BrightnessReading> => {
|
|
66
|
+
if (disposed) throw new Error("Brightness provider is disposed")
|
|
67
|
+
let result
|
|
68
|
+
try {
|
|
69
|
+
result = await executor.run(BRIGHTNESS_BIN, ["-l"], { timeoutMs: 2_000 })
|
|
70
|
+
} catch (err) {
|
|
71
|
+
warnMissing((err as Error).message)
|
|
72
|
+
return nullProvider.getCurrent()
|
|
73
|
+
}
|
|
74
|
+
if (result.exitCode !== 0) {
|
|
75
|
+
warnMissing(result.stderr.trim() || `exit ${result.exitCode}`)
|
|
76
|
+
return nullProvider.getCurrent()
|
|
77
|
+
}
|
|
78
|
+
const parsed = parseBrightnessList(result.stdout)
|
|
79
|
+
if (parsed === null) {
|
|
80
|
+
logger.warn(
|
|
81
|
+
{ stdout: result.stdout.slice(0, 200) },
|
|
82
|
+
"brightness: could not parse `brightness -l` output",
|
|
83
|
+
)
|
|
84
|
+
return nullProvider.getCurrent()
|
|
85
|
+
}
|
|
86
|
+
return parsed
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const setBrightness = async (value: number): Promise<void> => {
|
|
90
|
+
if (disposed) throw new Error("Brightness provider is disposed")
|
|
91
|
+
const fraction = Math.max(0, Math.min(100, Math.round(value))) / 100
|
|
92
|
+
let result
|
|
93
|
+
try {
|
|
94
|
+
result = await executor.run(BRIGHTNESS_BIN, [fraction.toFixed(3)], {
|
|
95
|
+
timeoutMs: 2_000,
|
|
96
|
+
})
|
|
97
|
+
} catch (err) {
|
|
98
|
+
warnMissing((err as Error).message)
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
if (result.exitCode !== 0) {
|
|
102
|
+
warnMissing(result.stderr.trim() || `exit ${result.exitCode}`)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { getCurrent, setBrightness, stop }
|
|
107
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type pino from "pino"
|
|
2
|
+
|
|
3
|
+
import { ProviderError } from "@/system/providers/error"
|
|
4
|
+
|
|
5
|
+
import { createDarwinBrightnessProvider } from "./darwin"
|
|
6
|
+
import { createLinuxBrightnessProvider } from "./linux"
|
|
7
|
+
import { type CommandExecutor } from "@/system/providers/shared"
|
|
8
|
+
import { createWindowsBrightnessProvider } from "./windows"
|
|
9
|
+
|
|
10
|
+
export interface BrightnessReading {
|
|
11
|
+
readonly value: number
|
|
12
|
+
readonly max: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BrightnessProvider {
|
|
16
|
+
getCurrent(): Promise<BrightnessReading>
|
|
17
|
+
setBrightness(value: number): Promise<void>
|
|
18
|
+
stop(): Promise<void>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const createNullBrightnessProvider = (
|
|
22
|
+
logger?: pino.Logger,
|
|
23
|
+
): BrightnessProvider => {
|
|
24
|
+
if (logger) {
|
|
25
|
+
logger.warn(
|
|
26
|
+
{ provider: "brightness" },
|
|
27
|
+
"OS brightness provider unavailable, using null provider",
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
async getCurrent(): Promise<BrightnessReading> {
|
|
32
|
+
return { value: 0, max: 100 }
|
|
33
|
+
},
|
|
34
|
+
async setBrightness(_value: number): Promise<void> {
|
|
35
|
+
throw new ProviderError(
|
|
36
|
+
"NOT_AVAILABLE",
|
|
37
|
+
"Brightness provider not available on this platform",
|
|
38
|
+
)
|
|
39
|
+
},
|
|
40
|
+
async stop() {
|
|
41
|
+
return
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface CreateBrightnessProviderOptions {
|
|
47
|
+
readonly executor: CommandExecutor
|
|
48
|
+
readonly platform?: NodeJS.Platform
|
|
49
|
+
readonly env?: Readonly<Record<string, string>>
|
|
50
|
+
readonly logger: pino.Logger
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const createBrightnessProvider = (
|
|
54
|
+
options: CreateBrightnessProviderOptions,
|
|
55
|
+
): BrightnessProvider => {
|
|
56
|
+
const platform = options.platform ?? process.platform
|
|
57
|
+
if (platform === "linux") {
|
|
58
|
+
return createLinuxBrightnessProvider({
|
|
59
|
+
executor: options.executor,
|
|
60
|
+
env: options.env,
|
|
61
|
+
logger: options.logger,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
if (platform === "darwin") {
|
|
65
|
+
return createDarwinBrightnessProvider({
|
|
66
|
+
executor: options.executor,
|
|
67
|
+
logger: options.logger,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
if (platform === "win32") {
|
|
71
|
+
return createWindowsBrightnessProvider({
|
|
72
|
+
executor: options.executor,
|
|
73
|
+
logger: options.logger,
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
void createNullBrightnessProvider(options.logger)
|
|
77
|
+
throw new ProviderError(
|
|
78
|
+
"UNSUPPORTED_PLATFORM",
|
|
79
|
+
`Brightness provider not implemented for platform '${platform}' in this build`,
|
|
80
|
+
)
|
|
81
|
+
}
|