@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,486 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
EXTENSION_INSTALL_URL,
|
|
5
|
+
hasWaylandGnomeSession,
|
|
6
|
+
} from "../providers/active-app/wayland-gnome"
|
|
7
|
+
import type { CommandExecutor } from "../providers/shared"
|
|
8
|
+
import { ACCESSIBILITY_SETTINGS_URL, UDEV_RULES_PATH } from "./types"
|
|
9
|
+
|
|
10
|
+
export { ACCESSIBILITY_SETTINGS_URL } from "./types"
|
|
11
|
+
import {
|
|
12
|
+
type CapabilityName,
|
|
13
|
+
type CapabilityProbe,
|
|
14
|
+
type DesktopSession,
|
|
15
|
+
type PackageManager,
|
|
16
|
+
type ProbeDeps,
|
|
17
|
+
type SystemReport,
|
|
18
|
+
type UdevProbe,
|
|
19
|
+
type ConfigProbe,
|
|
20
|
+
} from "./types"
|
|
21
|
+
|
|
22
|
+
const STREAM_DECK_PRODUCT_IDS = [
|
|
23
|
+
"0060",
|
|
24
|
+
"006c",
|
|
25
|
+
"006d",
|
|
26
|
+
"006e",
|
|
27
|
+
"0080",
|
|
28
|
+
"0084",
|
|
29
|
+
"0086",
|
|
30
|
+
"0090",
|
|
31
|
+
] as const
|
|
32
|
+
|
|
33
|
+
const PCMAN_PM_BINS: ReadonlyArray<{
|
|
34
|
+
readonly pm: PackageManager
|
|
35
|
+
readonly probe: ReadonlyArray<string>
|
|
36
|
+
}> = [
|
|
37
|
+
{ pm: "apt", probe: ["apt-get", "apt"] },
|
|
38
|
+
{ pm: "dnf", probe: ["dnf"] },
|
|
39
|
+
{ pm: "pacman", probe: ["pacman"] },
|
|
40
|
+
{ pm: "zypper", probe: ["zypper"] },
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
const detectPackageManager = async (
|
|
44
|
+
platform: string,
|
|
45
|
+
executor: CommandExecutor,
|
|
46
|
+
extraFsProbe?: (command: string) => boolean,
|
|
47
|
+
): Promise<PackageManager> => {
|
|
48
|
+
if (platform === "darwin") {
|
|
49
|
+
const brew = await probeCommand(executor, "brew", extraFsProbe)
|
|
50
|
+
return brew ? "brew" : "none"
|
|
51
|
+
}
|
|
52
|
+
if (platform !== "linux") return "none"
|
|
53
|
+
for (const { pm, probe } of PCMAN_PM_BINS) {
|
|
54
|
+
for (const bin of probe) {
|
|
55
|
+
if (await probeCommand(executor, bin, extraFsProbe)) return pm
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return "none"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const detectSession = (env: NodeJS.ProcessEnv): DesktopSession => {
|
|
62
|
+
if (env["XDG_SESSION_TYPE"] === "wayland") return "wayland"
|
|
63
|
+
if (env["XDG_SESSION_TYPE"] === "x11") return "x11"
|
|
64
|
+
if (env["WAYLAND_DISPLAY"] !== undefined && env["WAYLAND_DISPLAY"] !== "") {
|
|
65
|
+
return "wayland"
|
|
66
|
+
}
|
|
67
|
+
if (env["DISPLAY"] !== undefined && env["DISPLAY"] !== "") return "x11"
|
|
68
|
+
return "unknown"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const detectStreamDeck = (
|
|
72
|
+
platforms: ReadonlyArray<string>,
|
|
73
|
+
syncRunner: (cmd: string) => string,
|
|
74
|
+
): { connected: boolean; matched: ReadonlyArray<string> } => {
|
|
75
|
+
if (!platforms.includes("linux")) return { connected: false, matched: [] }
|
|
76
|
+
const candidates = ["lsusb", "/usr/bin/lsusb", "/usr/sbin/lsusb"]
|
|
77
|
+
let raw = ""
|
|
78
|
+
for (const bin of candidates) {
|
|
79
|
+
try {
|
|
80
|
+
raw = syncRunner(bin)
|
|
81
|
+
if (raw.length > 0) break
|
|
82
|
+
} catch {
|
|
83
|
+
// try next candidate
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (raw.length === 0) return { connected: false, matched: [] }
|
|
87
|
+
const matched: string[] = []
|
|
88
|
+
for (const pid of STREAM_DECK_PRODUCT_IDS) {
|
|
89
|
+
const re = new RegExp(`0fd9:${pid}\\b`, "i")
|
|
90
|
+
if (re.test(raw)) matched.push(pid)
|
|
91
|
+
}
|
|
92
|
+
return { connected: matched.length > 0, matched }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const probeViaCommandV = async (
|
|
96
|
+
executor: CommandExecutor,
|
|
97
|
+
command: string,
|
|
98
|
+
): Promise<boolean> => {
|
|
99
|
+
// ponytail: `command` is a POSIX shell builtin, not a binary.
|
|
100
|
+
// execFile can't run builtins directly — wrap in sh -c so the call
|
|
101
|
+
// works under real executors as well as test mocks. Argument is
|
|
102
|
+
// shell-quoted to keep the call single-token.
|
|
103
|
+
const quoted = `'${command.replaceAll(`'`, `'\\''`)}'`
|
|
104
|
+
const result = await executor.run("sh", ["-c", `command -v ${quoted}`])
|
|
105
|
+
return result.exitCode === 0 && result.stdout.trim().length > 0
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const probeViaVersion = async (
|
|
109
|
+
executor: CommandExecutor,
|
|
110
|
+
command: string,
|
|
111
|
+
): Promise<boolean> => {
|
|
112
|
+
try {
|
|
113
|
+
const result = await executor.run(command, ["--version"], {
|
|
114
|
+
timeoutMs: 1_000,
|
|
115
|
+
})
|
|
116
|
+
return result.exitCode === 0
|
|
117
|
+
} catch {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const probeCommand = async (
|
|
123
|
+
executor: CommandExecutor,
|
|
124
|
+
command: string,
|
|
125
|
+
extraFsProbe?: (command: string) => boolean,
|
|
126
|
+
): Promise<boolean> => {
|
|
127
|
+
if (await probeViaCommandV(executor, command)) return true
|
|
128
|
+
if (extraFsProbe?.(command) === true) return true
|
|
129
|
+
return await probeViaVersion(executor, command)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const probeCapability = async (
|
|
133
|
+
name: CapabilityName,
|
|
134
|
+
candidates: ReadonlyArray<string>,
|
|
135
|
+
preferred: string,
|
|
136
|
+
reason: string,
|
|
137
|
+
executor: CommandExecutor,
|
|
138
|
+
extraFsProbe?: (command: string) => boolean,
|
|
139
|
+
): Promise<CapabilityProbe> => {
|
|
140
|
+
const availability = await Promise.all(
|
|
141
|
+
candidates.map((cmd) => probeCommand(executor, cmd, extraFsProbe)),
|
|
142
|
+
)
|
|
143
|
+
const found = candidates.filter((_, idx) => availability[idx])
|
|
144
|
+
const missing = candidates.filter((_, idx) => !availability[idx])
|
|
145
|
+
return {
|
|
146
|
+
name,
|
|
147
|
+
available: found.length > 0,
|
|
148
|
+
toolInstalled: found.length > 0,
|
|
149
|
+
permission: null,
|
|
150
|
+
missing,
|
|
151
|
+
preferred,
|
|
152
|
+
reason,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ponytail: on macOS the mere presence of `osascript` proves nothing — it ships
|
|
157
|
+
// with the OS, so the capability probes always said "all present" while every
|
|
158
|
+
// UI-scripting call failed at runtime with "osascript is not allowed assistive
|
|
159
|
+
// access (-1719)". Key macros (`keystroke`/`key code`) and window-title reads
|
|
160
|
+
// both need an Accessibility (TCC) grant for whichever binary hosts the script.
|
|
161
|
+
// `UI elements enabled` is the documented, side-effect-free way to ask.
|
|
162
|
+
export const ACCESSIBILITY_HINT =
|
|
163
|
+
"grant Accessibility to your terminal (or the SirenoDeck app) in System Settings → Privacy & Security → Accessibility, then restart it"
|
|
164
|
+
|
|
165
|
+
const UI_ELEMENTS_SCRIPT = `tell application "System Events" to get UI elements enabled`
|
|
166
|
+
|
|
167
|
+
export const hasDarwinAccessibility = async (
|
|
168
|
+
executor: CommandExecutor,
|
|
169
|
+
): Promise<boolean> => {
|
|
170
|
+
try {
|
|
171
|
+
const result = await executor.run("osascript", ["-e", UI_ELEMENTS_SCRIPT], {
|
|
172
|
+
timeoutMs: 2_000,
|
|
173
|
+
})
|
|
174
|
+
return (
|
|
175
|
+
result.exitCode === 0 && result.stdout.trim().toLowerCase() === "true"
|
|
176
|
+
)
|
|
177
|
+
} catch {
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Wraps a darwin capability that needs UI scripting: the binary must exist AND
|
|
184
|
+
* the Accessibility grant must be in place, otherwise the capability is
|
|
185
|
+
* reported missing with an actionable reason instead of a false "present".
|
|
186
|
+
*/
|
|
187
|
+
const probeDarwinUiScripting = async (
|
|
188
|
+
name: CapabilityName,
|
|
189
|
+
reason: string,
|
|
190
|
+
executor: CommandExecutor,
|
|
191
|
+
extraFsProbe?: (command: string) => boolean,
|
|
192
|
+
): Promise<CapabilityProbe> => {
|
|
193
|
+
const base = await probeCapability(
|
|
194
|
+
name,
|
|
195
|
+
["osascript"],
|
|
196
|
+
"osascript",
|
|
197
|
+
reason,
|
|
198
|
+
executor,
|
|
199
|
+
extraFsProbe,
|
|
200
|
+
)
|
|
201
|
+
if (!base.available) return base
|
|
202
|
+
const granted = await hasDarwinAccessibility(executor)
|
|
203
|
+
const permission = {
|
|
204
|
+
label: "Accessibility",
|
|
205
|
+
granted,
|
|
206
|
+
hint: ACCESSIBILITY_HINT,
|
|
207
|
+
settingsUrl: ACCESSIBILITY_SETTINGS_URL,
|
|
208
|
+
}
|
|
209
|
+
if (granted) return { ...base, permission }
|
|
210
|
+
return {
|
|
211
|
+
...base,
|
|
212
|
+
available: false,
|
|
213
|
+
// toolInstalled stays true: osascript ships with macOS. Only the grant is
|
|
214
|
+
// missing, and `missing` keeps the sentinel so existing callers that gate
|
|
215
|
+
// on it (the install plan) behave as before.
|
|
216
|
+
permission,
|
|
217
|
+
missing: ["accessibility-permission"],
|
|
218
|
+
reason: `osascript is installed but has no Accessibility permission — ${ACCESSIBILITY_HINT}`,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const probeKeyMacro = (
|
|
223
|
+
platform: string,
|
|
224
|
+
executor: CommandExecutor,
|
|
225
|
+
extraFsProbe?: (command: string) => boolean,
|
|
226
|
+
): Promise<CapabilityProbe> => {
|
|
227
|
+
if (platform === "darwin") {
|
|
228
|
+
return probeDarwinUiScripting(
|
|
229
|
+
"keyMacro",
|
|
230
|
+
"macOS uses osascript for key macros.",
|
|
231
|
+
executor,
|
|
232
|
+
extraFsProbe,
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
if (platform === "win32") {
|
|
236
|
+
return probeCapability(
|
|
237
|
+
"keyMacro",
|
|
238
|
+
["powershell"],
|
|
239
|
+
"powershell",
|
|
240
|
+
"Windows uses PowerShell SendInput for key macros.",
|
|
241
|
+
executor,
|
|
242
|
+
extraFsProbe,
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
return probeCapability(
|
|
246
|
+
"keyMacro",
|
|
247
|
+
["ydotool", "wtype", "xdotool", "dotool"],
|
|
248
|
+
"ydotool",
|
|
249
|
+
"Install ydotool (most compositors) or wtype (wlroots only).",
|
|
250
|
+
executor,
|
|
251
|
+
extraFsProbe,
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const probeClipboard = (
|
|
256
|
+
platform: string,
|
|
257
|
+
executor: CommandExecutor,
|
|
258
|
+
extraFsProbe?: (command: string) => boolean,
|
|
259
|
+
): Promise<CapabilityProbe> => {
|
|
260
|
+
if (platform === "darwin") {
|
|
261
|
+
return probeCapability(
|
|
262
|
+
"clipboard",
|
|
263
|
+
["pbcopy"],
|
|
264
|
+
"pbcopy",
|
|
265
|
+
"macOS ships pbcopy.",
|
|
266
|
+
executor,
|
|
267
|
+
extraFsProbe,
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
if (platform === "win32") {
|
|
271
|
+
return probeCapability(
|
|
272
|
+
"clipboard",
|
|
273
|
+
["clip"],
|
|
274
|
+
"clip",
|
|
275
|
+
"Windows ships clip.exe.",
|
|
276
|
+
executor,
|
|
277
|
+
extraFsProbe,
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
return probeCapability(
|
|
281
|
+
"clipboard",
|
|
282
|
+
["wl-copy"],
|
|
283
|
+
"wl-copy",
|
|
284
|
+
"Install wl-clipboard (provides wl-copy).",
|
|
285
|
+
executor,
|
|
286
|
+
extraFsProbe,
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const probeNotification = (
|
|
291
|
+
platform: string,
|
|
292
|
+
executor: CommandExecutor,
|
|
293
|
+
extraFsProbe?: (command: string) => boolean,
|
|
294
|
+
): Promise<CapabilityProbe> => {
|
|
295
|
+
if (platform === "darwin") {
|
|
296
|
+
return probeCapability(
|
|
297
|
+
"notification",
|
|
298
|
+
["osascript"],
|
|
299
|
+
"osascript",
|
|
300
|
+
"macOS uses osascript for notifications.",
|
|
301
|
+
executor,
|
|
302
|
+
extraFsProbe,
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
if (platform === "win32") {
|
|
306
|
+
return probeCapability(
|
|
307
|
+
"notification",
|
|
308
|
+
["powershell"],
|
|
309
|
+
"powershell",
|
|
310
|
+
"Windows uses PowerShell NotifyIcon.",
|
|
311
|
+
executor,
|
|
312
|
+
extraFsProbe,
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
return probeCapability(
|
|
316
|
+
"notification",
|
|
317
|
+
["notify-send"],
|
|
318
|
+
"notify-send",
|
|
319
|
+
"Install libnotify (provides notify-send).",
|
|
320
|
+
executor,
|
|
321
|
+
extraFsProbe,
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const probeActiveApp = async (
|
|
326
|
+
platform: string,
|
|
327
|
+
env: NodeJS.ProcessEnv,
|
|
328
|
+
executor: CommandExecutor,
|
|
329
|
+
extraFsProbe?: (command: string) => boolean,
|
|
330
|
+
): Promise<CapabilityProbe> => {
|
|
331
|
+
if (platform === "darwin") {
|
|
332
|
+
// Without the grant the provider still reports the app name and pid (those
|
|
333
|
+
// need no permission) but never a window title, so this is a soft miss.
|
|
334
|
+
return probeDarwinUiScripting(
|
|
335
|
+
"activeApp",
|
|
336
|
+
"macOS uses AppleScript for active-app detection; window titles need Accessibility.",
|
|
337
|
+
executor,
|
|
338
|
+
extraFsProbe,
|
|
339
|
+
)
|
|
340
|
+
}
|
|
341
|
+
if (platform === "win32") {
|
|
342
|
+
return probeCapability(
|
|
343
|
+
"activeApp",
|
|
344
|
+
["powershell"],
|
|
345
|
+
"powershell",
|
|
346
|
+
"Windows uses PowerShell UIAutomation for active-app detection.",
|
|
347
|
+
executor,
|
|
348
|
+
extraFsProbe,
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
const session = detectSession(env)
|
|
352
|
+
if (await hasWaylandGnomeSession({ env, executor })) {
|
|
353
|
+
return {
|
|
354
|
+
name: "activeApp",
|
|
355
|
+
available: true,
|
|
356
|
+
toolInstalled: true,
|
|
357
|
+
permission: null,
|
|
358
|
+
missing: [],
|
|
359
|
+
preferred: "gnome-shell-extension",
|
|
360
|
+
reason: `Wayland GNOME requires the 'Window Calls Extended' extension (${EXTENSION_INSTALL_URL}). The wizard can detect this — install it from the GNOME extensions website and re-run.`,
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (session === "x11") {
|
|
364
|
+
return probeCapability(
|
|
365
|
+
"activeApp",
|
|
366
|
+
["xdotool", "xprop"],
|
|
367
|
+
"xdotool",
|
|
368
|
+
"Install xdotool and xprop for active-app detection on X11.",
|
|
369
|
+
executor,
|
|
370
|
+
extraFsProbe,
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
return probeCapability(
|
|
374
|
+
"activeApp",
|
|
375
|
+
["xdotool"],
|
|
376
|
+
"xdotool",
|
|
377
|
+
"No active-app provider detected for this session. Install xdotool or switch to a supported session.",
|
|
378
|
+
executor,
|
|
379
|
+
extraFsProbe,
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const probeUdev = (
|
|
384
|
+
platform: string,
|
|
385
|
+
rulesPath: string,
|
|
386
|
+
fileExists: (path: string) => boolean,
|
|
387
|
+
readFile: (path: string) => string | null,
|
|
388
|
+
streamDeck: { connected: boolean; matched: ReadonlyArray<string> },
|
|
389
|
+
): UdevProbe => {
|
|
390
|
+
if (platform !== "linux") {
|
|
391
|
+
return {
|
|
392
|
+
rulesInstalled: true,
|
|
393
|
+
rulesPath,
|
|
394
|
+
streamDeckConnected: false,
|
|
395
|
+
matchedProductIds: [],
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const contents = fileExists(rulesPath) ? readFile(rulesPath) : null
|
|
399
|
+
return {
|
|
400
|
+
rulesInstalled:
|
|
401
|
+
contents !== null &&
|
|
402
|
+
contents.includes('SUBSYSTEM=="usb"') &&
|
|
403
|
+
contents.includes('ATTRS{idVendor}=="0fd9"'),
|
|
404
|
+
rulesPath,
|
|
405
|
+
streamDeckConnected: streamDeck.connected,
|
|
406
|
+
matchedProductIds: streamDeck.matched,
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ponytail: an explicit `--config` is the config for this run — report on THAT
|
|
411
|
+
// file, not on the XDG default the user never asked for. The XDG path stays the
|
|
412
|
+
// answer (and the seed target) when no explicit path was given.
|
|
413
|
+
const probeConfig = (
|
|
414
|
+
xdgConfigHome: string,
|
|
415
|
+
fileExists: (path: string) => boolean,
|
|
416
|
+
configPath?: string,
|
|
417
|
+
): ConfigProbe => {
|
|
418
|
+
const path =
|
|
419
|
+
configPath !== undefined && configPath !== ""
|
|
420
|
+
? configPath
|
|
421
|
+
: `${xdgConfigHome}/sirenodeck/config.yml`
|
|
422
|
+
return { exists: fileExists(path), path }
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export const probeAll = async (deps: ProbeDeps): Promise<SystemReport> => {
|
|
426
|
+
const {
|
|
427
|
+
platform,
|
|
428
|
+
homeDir,
|
|
429
|
+
xdgConfigHome,
|
|
430
|
+
env,
|
|
431
|
+
executor,
|
|
432
|
+
extraFsProbe,
|
|
433
|
+
fileExists,
|
|
434
|
+
readFile,
|
|
435
|
+
configPath,
|
|
436
|
+
} = deps
|
|
437
|
+
|
|
438
|
+
const session = detectSession(env)
|
|
439
|
+
const packageManager = await detectPackageManager(
|
|
440
|
+
platform,
|
|
441
|
+
executor,
|
|
442
|
+
extraFsProbe,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
const lsusbSync = (binary: string): string => {
|
|
446
|
+
try {
|
|
447
|
+
const out = execFileSync(binary, [], {
|
|
448
|
+
encoding: "utf8",
|
|
449
|
+
timeout: 2_000,
|
|
450
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
451
|
+
})
|
|
452
|
+
return out
|
|
453
|
+
} catch {
|
|
454
|
+
return ""
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const streamDeck = detectStreamDeck([platform], lsusbSync)
|
|
459
|
+
|
|
460
|
+
const capabilities = {
|
|
461
|
+
keyMacro: await probeKeyMacro(platform, executor, extraFsProbe),
|
|
462
|
+
clipboard: await probeClipboard(platform, executor, extraFsProbe),
|
|
463
|
+
notification: await probeNotification(platform, executor, extraFsProbe),
|
|
464
|
+
activeApp: await probeActiveApp(platform, env, executor, extraFsProbe),
|
|
465
|
+
} as const
|
|
466
|
+
|
|
467
|
+
const udev = probeUdev(
|
|
468
|
+
platform,
|
|
469
|
+
UDEV_RULES_PATH,
|
|
470
|
+
fileExists,
|
|
471
|
+
readFile,
|
|
472
|
+
streamDeck,
|
|
473
|
+
)
|
|
474
|
+
const config = probeConfig(xdgConfigHome, fileExists, configPath)
|
|
475
|
+
|
|
476
|
+
return {
|
|
477
|
+
platform,
|
|
478
|
+
homeDir,
|
|
479
|
+
xdgConfigHome,
|
|
480
|
+
session,
|
|
481
|
+
packageManager,
|
|
482
|
+
capabilities,
|
|
483
|
+
udev,
|
|
484
|
+
config,
|
|
485
|
+
}
|
|
486
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs"
|
|
2
|
+
import { homedir } from "node:os"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
|
|
5
|
+
export interface RuntimeFeatureProbe {
|
|
6
|
+
readonly available: boolean
|
|
7
|
+
readonly reason?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// ponytail: lightweight runtime probes for the startup banner. Unlike the
|
|
11
|
+
// full system probe (`probeAll`) these don't run subprocesses for every
|
|
12
|
+
// capability — they just sanity-check that the resources exist. 2s budget
|
|
13
|
+
// per probe; failures fall back to ✗ with a short reason.
|
|
14
|
+
|
|
15
|
+
const REASON_MAX = 40
|
|
16
|
+
|
|
17
|
+
const truncate = (s: string): string =>
|
|
18
|
+
s.length <= REASON_MAX ? s : `${s.slice(0, REASON_MAX - 1)}…`
|
|
19
|
+
|
|
20
|
+
// ponytail: chromium can legitimately live in either of two places. The
|
|
21
|
+
// first-run bootstrap pins PLAYWRIGHT_BROWSERS_PATH to
|
|
22
|
+
// ~/.cache/sirenodeck/playwright, but a `playwright install` run by hand — the
|
|
23
|
+
// documented fix, and what a dev checkout needs — puts it in Playwright's own
|
|
24
|
+
// per-OS default. Checking only the sirenodeck path reported "not installed"
|
|
25
|
+
// on a machine whose renderer was working fine.
|
|
26
|
+
const playwrightDefaultBrowsersDir = (): string => {
|
|
27
|
+
switch (process.platform) {
|
|
28
|
+
case "darwin":
|
|
29
|
+
return join(homedir(), "Library", "Caches", "ms-playwright")
|
|
30
|
+
case "win32":
|
|
31
|
+
return join(process.env["LOCALAPPDATA"] ?? homedir(), "ms-playwright")
|
|
32
|
+
default:
|
|
33
|
+
return join(homedir(), ".cache", "ms-playwright")
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const hasChromium = (dir: string): boolean => {
|
|
38
|
+
if (!existsSync(dir)) return false
|
|
39
|
+
try {
|
|
40
|
+
return readdirSync(dir).some((e) => e.startsWith("chromium"))
|
|
41
|
+
} catch {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const probeMediaAccess = async (): Promise<RuntimeFeatureProbe> => {
|
|
47
|
+
const explicit = process.env["PLAYWRIGHT_BROWSERS_PATH"]
|
|
48
|
+
const candidates =
|
|
49
|
+
explicit !== undefined && explicit !== ""
|
|
50
|
+
? [explicit]
|
|
51
|
+
: [
|
|
52
|
+
join(homedir(), ".cache", "sirenodeck", "playwright"),
|
|
53
|
+
playwrightDefaultBrowsersDir(),
|
|
54
|
+
]
|
|
55
|
+
if (candidates.some(hasChromium)) return { available: true }
|
|
56
|
+
return { available: false, reason: truncate("chromium not installed") }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const probeCommandExecution = async (): Promise<RuntimeFeatureProbe> => {
|
|
60
|
+
const shell =
|
|
61
|
+
process.platform === "win32"
|
|
62
|
+
? `${process.env["SystemRoot"] ?? "C:\\Windows"}\\System32\\cmd.exe`
|
|
63
|
+
: "/bin/sh"
|
|
64
|
+
if (!existsSync(shell)) {
|
|
65
|
+
return { available: false, reason: truncate(`shell missing: ${shell}`) }
|
|
66
|
+
}
|
|
67
|
+
return { available: true }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const probeInternetAccess = async (): Promise<RuntimeFeatureProbe> => {
|
|
71
|
+
if (typeof fetch !== "function") {
|
|
72
|
+
return { available: false, reason: "fetch unavailable" }
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const res = await fetch("https://1.1.1.1/", {
|
|
76
|
+
method: "HEAD",
|
|
77
|
+
signal: AbortSignal.timeout(2_000),
|
|
78
|
+
})
|
|
79
|
+
return res.ok || (res.status >= 200 && res.status < 500)
|
|
80
|
+
? { available: true }
|
|
81
|
+
: { available: false, reason: truncate(`HTTP ${res.status}`) }
|
|
82
|
+
} catch (err) {
|
|
83
|
+
return { available: false, reason: truncate(`unreachable: ${String(err)}`) }
|
|
84
|
+
}
|
|
85
|
+
}
|