@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,275 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CapabilityName,
|
|
3
|
+
CapabilityProbe,
|
|
4
|
+
InstallStep,
|
|
5
|
+
InstallStepResult,
|
|
6
|
+
SystemReport,
|
|
7
|
+
SystemReportSummary,
|
|
8
|
+
} from "./types"
|
|
9
|
+
|
|
10
|
+
const SESSION_LABEL: Readonly<Record<string, string>> = {
|
|
11
|
+
wayland: "Wayland",
|
|
12
|
+
x11: "X11",
|
|
13
|
+
unknown: "unknown",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ponytail: ANSI helpers, no dep. `colorette` would pull in transitive types
|
|
17
|
+
// for a single use site — terminal escape sequences are stable. Returns the
|
|
18
|
+
// input untouched when stdout is not a TTY so piped output stays clean.
|
|
19
|
+
const useColor = (): boolean =>
|
|
20
|
+
Boolean(process.stdout.isTTY) && process.env["NO_COLOR"] === undefined
|
|
21
|
+
|
|
22
|
+
const ESC = "\u001b["
|
|
23
|
+
export const color = {
|
|
24
|
+
green: (s: string): string => (useColor() ? `${ESC}32m${s}${ESC}0m` : s),
|
|
25
|
+
red: (s: string): string => (useColor() ? `${ESC}31m${s}${ESC}0m` : s),
|
|
26
|
+
yellow: (s: string): string => (useColor() ? `${ESC}33m${s}${ESC}0m` : s),
|
|
27
|
+
dim: (s: string): string => (useColor() ? `${ESC}2m${s}${ESC}0m` : s),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const stripAnsi = (s: string): string =>
|
|
31
|
+
s.replace(/\u001b\[[0-9;]*m/g, "")
|
|
32
|
+
|
|
33
|
+
export const summarizeReport = (report: SystemReport): SystemReportSummary => {
|
|
34
|
+
const missingCapabilities: Array<
|
|
35
|
+
"keyMacro" | "clipboard" | "notification" | "activeApp"
|
|
36
|
+
> = []
|
|
37
|
+
for (const [name, cap] of Object.entries(report.capabilities)) {
|
|
38
|
+
if (!cap.available) {
|
|
39
|
+
missingCapabilities.push(
|
|
40
|
+
name as "keyMacro" | "clipboard" | "notification" | "activeApp",
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const lines: string[] = []
|
|
46
|
+
const ok =
|
|
47
|
+
missingCapabilities.length === 0 &&
|
|
48
|
+
report.udev.rulesInstalled &&
|
|
49
|
+
report.config.exists
|
|
50
|
+
|
|
51
|
+
lines.push(
|
|
52
|
+
`Platform: ${report.platform} (${SESSION_LABEL[report.session] ?? "unknown"} session)`,
|
|
53
|
+
)
|
|
54
|
+
lines.push(`Package manager: ${report.packageManager}`)
|
|
55
|
+
lines.push(`Config target: ${report.config.path}`)
|
|
56
|
+
|
|
57
|
+
if (missingCapabilities.length === 0) {
|
|
58
|
+
lines.push("Capabilities: all present")
|
|
59
|
+
} else {
|
|
60
|
+
// ponytail: same two problems the interactive panel had — internal keys
|
|
61
|
+
// ("keyMacro") instead of names a user recognises, and the full remedy
|
|
62
|
+
// repeated once per capability that happens to need the same grant. Lead
|
|
63
|
+
// with the capability and print each distinct remedy once.
|
|
64
|
+
lines.push("Missing capabilities:")
|
|
65
|
+
const remedies: string[] = []
|
|
66
|
+
for (const name of missingCapabilities) {
|
|
67
|
+
const cap = report.capabilities[name]
|
|
68
|
+
const label = CAPABILITY_LABEL[name]
|
|
69
|
+
const permission = cap.permission
|
|
70
|
+
const blocked =
|
|
71
|
+
cap.toolInstalled && permission !== null && !permission.granted
|
|
72
|
+
const state = blocked
|
|
73
|
+
? `${cap.preferred} installed, ${permission.label} permission not granted`
|
|
74
|
+
: `${cap.preferred} not installed`
|
|
75
|
+
const remedy = blocked
|
|
76
|
+
? `${permission.label}: ${permission.hint}`
|
|
77
|
+
: cap.reason
|
|
78
|
+
if (!remedies.includes(remedy)) remedies.push(remedy)
|
|
79
|
+
lines.push(` - ${label}: ${state} [${remedies.indexOf(remedy) + 1}]`)
|
|
80
|
+
}
|
|
81
|
+
remedies.forEach((remedy, index) => {
|
|
82
|
+
lines.push(` [${index + 1}] ${remedy}`)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (report.platform === "linux") {
|
|
87
|
+
lines.push(
|
|
88
|
+
report.udev.rulesInstalled
|
|
89
|
+
? "udev rules: installed at " + report.udev.rulesPath
|
|
90
|
+
: "udev rules: missing at " + report.udev.rulesPath,
|
|
91
|
+
)
|
|
92
|
+
lines.push(
|
|
93
|
+
report.udev.streamDeckConnected
|
|
94
|
+
? "Stream Deck: connected (" +
|
|
95
|
+
report.udev.matchedProductIds.join(", ") +
|
|
96
|
+
")"
|
|
97
|
+
: "Stream Deck: not detected",
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
lines.push(
|
|
102
|
+
report.config.exists
|
|
103
|
+
? "Config: present"
|
|
104
|
+
: "Config: missing (run `sirenodeck system-requirements` to seed)",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
ok,
|
|
109
|
+
session: report.session,
|
|
110
|
+
packageManager: report.packageManager,
|
|
111
|
+
missingCapabilities,
|
|
112
|
+
udevMissing: !report.udev.rulesInstalled,
|
|
113
|
+
configMissing: !report.config.exists,
|
|
114
|
+
configPath: report.config.path,
|
|
115
|
+
streamDeckConnected: report.udev.streamDeckConnected,
|
|
116
|
+
lines,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ponytail: the panel used to lead with the tool name, so macOS printed
|
|
121
|
+
// "osascript" three times — once per capability that happens to be driven by
|
|
122
|
+
// AppleScript — and repeated the same 200-character Accessibility hint twice.
|
|
123
|
+
// The capability is what the user cares about and the tool is an
|
|
124
|
+
// implementation detail, so capability now leads and the long hints collapse
|
|
125
|
+
// into numbered footnotes shared by every row that needs them.
|
|
126
|
+
const CAPABILITY_LABEL: Readonly<Record<CapabilityName, string>> = {
|
|
127
|
+
keyMacro: "Key macros",
|
|
128
|
+
clipboard: "Clipboard",
|
|
129
|
+
notification: "Notifications",
|
|
130
|
+
activeApp: "Active app",
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const CAPABILITY_ORDER: ReadonlyArray<CapabilityName> = [
|
|
134
|
+
"keyMacro",
|
|
135
|
+
"clipboard",
|
|
136
|
+
"notification",
|
|
137
|
+
"activeApp",
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
const FOOTNOTE_WIDTH = 64
|
|
141
|
+
|
|
142
|
+
const wrapText = (text: string, width: number): string[] => {
|
|
143
|
+
const words = text.split(/\s+/).filter((w) => w.length > 0)
|
|
144
|
+
const lines: string[] = []
|
|
145
|
+
let current = ""
|
|
146
|
+
for (const word of words) {
|
|
147
|
+
if (current.length === 0) {
|
|
148
|
+
current = word
|
|
149
|
+
} else if (current.length + 1 + word.length <= width) {
|
|
150
|
+
current = `${current} ${word}`
|
|
151
|
+
} else {
|
|
152
|
+
lines.push(current)
|
|
153
|
+
current = word
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (current.length > 0) lines.push(current)
|
|
157
|
+
return lines.length > 0 ? lines : [""]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface CapabilityRow {
|
|
161
|
+
readonly mark: string
|
|
162
|
+
readonly label: string
|
|
163
|
+
readonly tool: string
|
|
164
|
+
readonly status: string
|
|
165
|
+
readonly note: number | null
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Splits a capability into the two independent facts the old renderer
|
|
170
|
+
* conflated: whether the tool is installed, and whether it has the permission
|
|
171
|
+
* it needs. A denied grant is not "Not installed".
|
|
172
|
+
*/
|
|
173
|
+
const describeCapability = (
|
|
174
|
+
cap: CapabilityProbe,
|
|
175
|
+
): { status: string; detail: string | null } => {
|
|
176
|
+
if (!cap.toolInstalled) {
|
|
177
|
+
return { status: color.red("not installed"), detail: cap.reason }
|
|
178
|
+
}
|
|
179
|
+
const permission = cap.permission
|
|
180
|
+
if (permission === null) {
|
|
181
|
+
return { status: color.green("installed"), detail: null }
|
|
182
|
+
}
|
|
183
|
+
if (permission.granted) {
|
|
184
|
+
return {
|
|
185
|
+
status: `${color.green("installed")}${color.dim(" · ")}${color.green(`${permission.label} granted`)}`,
|
|
186
|
+
detail: null,
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
status: `${color.green("installed")}${color.dim(" · ")}${color.red(`${permission.label} not granted`)}`,
|
|
191
|
+
detail: `${permission.label} permission — ${permission.hint}.`,
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export const formatCapabilityPanel = (
|
|
196
|
+
capabilities: Readonly<Record<CapabilityName, CapabilityProbe>>,
|
|
197
|
+
): string => {
|
|
198
|
+
const footnotes: string[] = []
|
|
199
|
+
const footnoteFor = (detail: string): number => {
|
|
200
|
+
const existing = footnotes.indexOf(detail)
|
|
201
|
+
if (existing !== -1) return existing + 1
|
|
202
|
+
footnotes.push(detail)
|
|
203
|
+
return footnotes.length
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const rows: CapabilityRow[] = []
|
|
207
|
+
for (const name of CAPABILITY_ORDER) {
|
|
208
|
+
const cap = capabilities[name]
|
|
209
|
+
if (cap === undefined) continue
|
|
210
|
+
const { status, detail } = describeCapability(cap)
|
|
211
|
+
rows.push({
|
|
212
|
+
mark: cap.available ? color.green("●") : color.red("○"),
|
|
213
|
+
label: CAPABILITY_LABEL[name],
|
|
214
|
+
tool: cap.preferred,
|
|
215
|
+
status,
|
|
216
|
+
note: detail === null ? null : footnoteFor(detail),
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const labelWidth = Math.max(...rows.map((r) => r.label.length))
|
|
221
|
+
const toolWidth = Math.max(...rows.map((r) => r.tool.length))
|
|
222
|
+
|
|
223
|
+
const lines = rows.map((r) => {
|
|
224
|
+
const label = `${r.label}:`.padEnd(labelWidth + 2)
|
|
225
|
+
const tool = color.dim(r.tool.padEnd(toolWidth))
|
|
226
|
+
const marker = r.note === null ? "" : color.dim(` [${r.note}]`)
|
|
227
|
+
return `${r.mark} ${label} ${tool} ${r.status}${marker}`
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
if (footnotes.length > 0) {
|
|
231
|
+
lines.push("")
|
|
232
|
+
footnotes.forEach((detail, index) => {
|
|
233
|
+
const wrapped = wrapText(detail, FOOTNOTE_WIDTH)
|
|
234
|
+
wrapped.forEach((line, lineIndex) => {
|
|
235
|
+
lines.push(
|
|
236
|
+
lineIndex === 0
|
|
237
|
+
? `${color.dim(`[${index + 1}]`)} ${line}`
|
|
238
|
+
: ` ${line}`,
|
|
239
|
+
)
|
|
240
|
+
})
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return lines.join("\n")
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export const formatStepInstructions = (step: InstallStep): string => {
|
|
248
|
+
if (step.manualInstructions.length > 0) return step.manualInstructions
|
|
249
|
+
if (step.packageManager === "none") {
|
|
250
|
+
return `No package manager detected. Install manually: ${step.packages.join(", ")}.`
|
|
251
|
+
}
|
|
252
|
+
const verb =
|
|
253
|
+
step.packageManager === "brew"
|
|
254
|
+
? "brew install"
|
|
255
|
+
: `sudo ${step.packageManager} install -y`
|
|
256
|
+
return `${verb} ${step.packages.join(" ")}`
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export const formatSummaryLine = (line: string): string => line
|
|
260
|
+
|
|
261
|
+
export const formatResultLine = (
|
|
262
|
+
step: InstallStep,
|
|
263
|
+
result: InstallStepResult,
|
|
264
|
+
): string => {
|
|
265
|
+
switch (result) {
|
|
266
|
+
case "installed":
|
|
267
|
+
return `${color.green("✓")} ${step.title}`
|
|
268
|
+
case "skipped":
|
|
269
|
+
return `${color.dim("·")} ${step.title} ${color.dim("(skipped)")}`
|
|
270
|
+
case "failed":
|
|
271
|
+
return `${color.red("✗")} ${step.title} ${color.red(`(failed — see ${step.manualInstructions.length > 0 ? "instructions below" : "logs"})`)}`
|
|
272
|
+
case "manual":
|
|
273
|
+
return `${color.dim("→")} ${step.title} ${color.dim(`(manual — ${step.manualInstructions.slice(0, 60)}…)`)}`
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type CapabilityName,
|
|
3
|
+
type CapabilityProbe,
|
|
4
|
+
type ConfigProbe,
|
|
5
|
+
type DesktopSession,
|
|
6
|
+
type InstallStep,
|
|
7
|
+
type InstallStepResult,
|
|
8
|
+
type PackageManager,
|
|
9
|
+
type ProbeDeps,
|
|
10
|
+
type SystemReport,
|
|
11
|
+
type SystemReportSummary,
|
|
12
|
+
type UdevProbe,
|
|
13
|
+
type WizardOutcome,
|
|
14
|
+
UDEV_RULES_PATH,
|
|
15
|
+
} from "./types"
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
probeAll,
|
|
19
|
+
ACCESSIBILITY_HINT,
|
|
20
|
+
ACCESSIBILITY_SETTINGS_URL,
|
|
21
|
+
hasDarwinAccessibility,
|
|
22
|
+
} from "./probe"
|
|
23
|
+
export { probeAllCached, resetProbeCache } from "./probe-cache"
|
|
24
|
+
export {
|
|
25
|
+
probeMediaAccess,
|
|
26
|
+
probeCommandExecution,
|
|
27
|
+
probeInternetAccess,
|
|
28
|
+
type RuntimeFeatureProbe,
|
|
29
|
+
} from "./runtime-features"
|
|
30
|
+
export {
|
|
31
|
+
buildInstallPlan,
|
|
32
|
+
needsConfigSeed,
|
|
33
|
+
DARWIN_ACCESSIBILITY_STEP_ID,
|
|
34
|
+
} from "./plan"
|
|
35
|
+
export {
|
|
36
|
+
formatCapabilityPanel,
|
|
37
|
+
formatResultLine,
|
|
38
|
+
formatStepInstructions,
|
|
39
|
+
formatSummaryLine,
|
|
40
|
+
summarizeReport,
|
|
41
|
+
} from "./format"
|
|
42
|
+
export { openSettingsUrl } from "./open-settings"
|
|
43
|
+
export { defaultConfigSourcePath, seedDefaultConfig } from "./config-seed"
|
|
44
|
+
export { isSudoNopasswd, runWithSudo, capturePassword } from "./sudo"
|
|
45
|
+
export type { SudoRunResult } from "./sudo"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CommandExecutor } from "../providers/shared"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Opens a System Settings pane by its `x-apple.systempreferences:` deep link.
|
|
5
|
+
*
|
|
6
|
+
* ponytail: the Accessibility grant is the one setup step no package manager
|
|
7
|
+
* can perform, and the old flow just printed a System Settings → Privacy &
|
|
8
|
+
* Security → Accessibility breadcrumb and left the user to navigate it. macOS
|
|
9
|
+
* can jump straight to the pane, so offer that instead of prose.
|
|
10
|
+
*
|
|
11
|
+
* Returns false (never throws) on non-darwin platforms or when `open` fails —
|
|
12
|
+
* the caller falls back to printing the manual instructions.
|
|
13
|
+
*/
|
|
14
|
+
export const openSettingsUrl = async (
|
|
15
|
+
executor: CommandExecutor,
|
|
16
|
+
url: string,
|
|
17
|
+
platform: string = process.platform,
|
|
18
|
+
): Promise<boolean> => {
|
|
19
|
+
if (platform !== "darwin") return false
|
|
20
|
+
try {
|
|
21
|
+
const result = await executor.run("open", [url])
|
|
22
|
+
return result.exitCode === 0
|
|
23
|
+
} catch {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { UDEV_RULES } from "../../device/linux-udev"
|
|
2
|
+
import { EXTENSION_INSTALL_URL } from "../providers/active-app/wayland-gnome"
|
|
3
|
+
import {
|
|
4
|
+
type CapabilityName,
|
|
5
|
+
type InstallStep,
|
|
6
|
+
type PackageManager,
|
|
7
|
+
type SystemReport,
|
|
8
|
+
ACCESSIBILITY_SETTINGS_URL,
|
|
9
|
+
UDEV_RULES_PATH,
|
|
10
|
+
} from "./types"
|
|
11
|
+
|
|
12
|
+
interface PackageMap {
|
|
13
|
+
readonly apt: ReadonlyArray<string>
|
|
14
|
+
readonly dnf: ReadonlyArray<string>
|
|
15
|
+
readonly pacman: ReadonlyArray<string>
|
|
16
|
+
readonly zypper: ReadonlyArray<string>
|
|
17
|
+
readonly brew: ReadonlyArray<string>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const KEYMACRO_PACKAGES: PackageMap = {
|
|
21
|
+
apt: ["ydotool"],
|
|
22
|
+
dnf: ["ydotool"],
|
|
23
|
+
pacman: ["ydotool"],
|
|
24
|
+
zypper: ["ydotool"],
|
|
25
|
+
brew: [],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const CLIPBOARD_WAYLAND_PACKAGES: PackageMap = {
|
|
29
|
+
apt: ["wl-clipboard"],
|
|
30
|
+
dnf: ["wl-clipboard"],
|
|
31
|
+
pacman: ["wl-clipboard"],
|
|
32
|
+
zypper: ["wl-clipboard"],
|
|
33
|
+
brew: [],
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CLIPBOARD_X11_PACKAGES: PackageMap = {
|
|
37
|
+
apt: ["xclip"],
|
|
38
|
+
dnf: ["xclip"],
|
|
39
|
+
pacman: ["xclip"],
|
|
40
|
+
zypper: ["xclip"],
|
|
41
|
+
brew: [],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const NOTIFICATION_PACKAGES: PackageMap = {
|
|
45
|
+
apt: ["libnotify-bin"],
|
|
46
|
+
dnf: ["libnotify"],
|
|
47
|
+
pacman: ["libnotify"],
|
|
48
|
+
zypper: ["libnotify"],
|
|
49
|
+
brew: [],
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const ACTIVEAPP_X11_PACKAGES: PackageMap = {
|
|
53
|
+
apt: ["xdotool", "x11-utils"],
|
|
54
|
+
dnf: ["xdotool", "xorg-x11-utils"],
|
|
55
|
+
pacman: ["xdotool"],
|
|
56
|
+
zypper: ["xdotool"],
|
|
57
|
+
brew: [],
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const resolvePackages = (
|
|
61
|
+
map: PackageMap,
|
|
62
|
+
pm: PackageManager,
|
|
63
|
+
): ReadonlyArray<string> => {
|
|
64
|
+
if (pm === "none") return []
|
|
65
|
+
return map[pm]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const capId = (name: CapabilityName): string => `cap:${name}`
|
|
69
|
+
|
|
70
|
+
const udevInstruction = (rulesPath: string): string =>
|
|
71
|
+
`sudo tee ${rulesPath} > /dev/null <<'EOF'
|
|
72
|
+
${UDEV_RULES.trimEnd()}
|
|
73
|
+
EOF
|
|
74
|
+
sudo udevadm control --reload-rules && sudo udevadm trigger`
|
|
75
|
+
|
|
76
|
+
const buildCapabilityStep = (
|
|
77
|
+
name: CapabilityName,
|
|
78
|
+
title: string,
|
|
79
|
+
description: string,
|
|
80
|
+
packages: ReadonlyArray<string>,
|
|
81
|
+
pm: PackageManager,
|
|
82
|
+
verifyCommand: string,
|
|
83
|
+
): InstallStep => ({
|
|
84
|
+
id: capId(name),
|
|
85
|
+
capability: name,
|
|
86
|
+
title,
|
|
87
|
+
description,
|
|
88
|
+
packageManager: pm,
|
|
89
|
+
packages,
|
|
90
|
+
sudo: pm !== "brew",
|
|
91
|
+
manualOnly: packages.length === 0,
|
|
92
|
+
manualInstructions:
|
|
93
|
+
packages.length === 0
|
|
94
|
+
? `No supported package manager found for this platform. Install ${name} manually for your distro.`
|
|
95
|
+
: pm === "none"
|
|
96
|
+
? `No package manager detected. Install manually: ${packages.join(", ")}.`
|
|
97
|
+
: "",
|
|
98
|
+
...(verifyCommand.length > 0 ? { verifyCommand } : {}),
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const buildUdevStep = (streamDeckConnected: boolean): InstallStep => ({
|
|
102
|
+
id: "udev:rules",
|
|
103
|
+
capability: "udev",
|
|
104
|
+
title: "Stream Deck udev rules",
|
|
105
|
+
description: streamDeckConnected
|
|
106
|
+
? "Stream Deck detected but udev rules are missing. Without them, the daemon can't access the device without sudo."
|
|
107
|
+
: "Install udev rules so a Stream Deck can be accessed without sudo when you plug one in.",
|
|
108
|
+
packageManager: "none",
|
|
109
|
+
packages: [],
|
|
110
|
+
sudo: true,
|
|
111
|
+
manualOnly: false,
|
|
112
|
+
manualInstructions: udevInstruction(UDEV_RULES_PATH),
|
|
113
|
+
verifyCommand: `test -f ${UDEV_RULES_PATH} && echo installed || echo missing`,
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const buildGnomeExtensionStep = (): InstallStep => ({
|
|
117
|
+
id: "cap:activeApp:gnome-extension",
|
|
118
|
+
capability: "activeApp",
|
|
119
|
+
title: "GNOME 'Window Calls Extended' extension",
|
|
120
|
+
description: `Wayland GNOME requires this extension for active-app detection. Install from ${EXTENSION_INSTALL_URL}.`,
|
|
121
|
+
packageManager: "none",
|
|
122
|
+
packages: [],
|
|
123
|
+
sudo: false,
|
|
124
|
+
manualOnly: true,
|
|
125
|
+
manualInstructions: `Open ${EXTENSION_INSTALL_URL} in your browser, toggle the extension ON, then log out / log in (or restart GNOME Shell).`,
|
|
126
|
+
verifyCommand: undefined,
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// ponytail: macOS UI scripting is gated by a TCC grant that no package manager
|
|
130
|
+
// can install, so this is manual-only. Before this step the wizard had no
|
|
131
|
+
// darwin branch at all — it printed "Capabilities: all present" while every
|
|
132
|
+
// keystroke silently failed with -1719.
|
|
133
|
+
export const DARWIN_ACCESSIBILITY_STEP_ID = "cap:darwin:accessibility"
|
|
134
|
+
|
|
135
|
+
const buildDarwinAccessibilityStep = (): InstallStep => ({
|
|
136
|
+
id: DARWIN_ACCESSIBILITY_STEP_ID,
|
|
137
|
+
capability: "keyMacro",
|
|
138
|
+
title: "macOS Accessibility permission",
|
|
139
|
+
description:
|
|
140
|
+
"Key macros and window-title detection drive the UI through AppleScript, which macOS gates behind Accessibility.",
|
|
141
|
+
packageManager: "none",
|
|
142
|
+
packages: [],
|
|
143
|
+
sudo: false,
|
|
144
|
+
manualOnly: true,
|
|
145
|
+
manualInstructions: `Open the pane directly: open "${ACCESSIBILITY_SETTINGS_URL}"
|
|
146
|
+
Then enable the app running sirenodeck (your terminal, or SirenoDeck.app) and restart it.
|
|
147
|
+
Verify with: osascript -e 'tell application "System Events" to get UI elements enabled' # should print true`,
|
|
148
|
+
verifyCommand: `osascript -e 'tell application "System Events" to get UI elements enabled'`,
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
export const buildInstallPlan = (report: SystemReport): InstallStep[] => {
|
|
152
|
+
const steps: InstallStep[] = []
|
|
153
|
+
const { platform, session, packageManager, capabilities, udev } = report
|
|
154
|
+
|
|
155
|
+
if (
|
|
156
|
+
platform === "darwin" &&
|
|
157
|
+
(!capabilities.keyMacro.available || !capabilities.activeApp.available)
|
|
158
|
+
) {
|
|
159
|
+
steps.push(buildDarwinAccessibilityStep())
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (capabilities.keyMacro.missing.length > 0 && platform === "linux") {
|
|
163
|
+
steps.push(
|
|
164
|
+
buildCapabilityStep(
|
|
165
|
+
"keyMacro",
|
|
166
|
+
"Key macro tool (ydotool)",
|
|
167
|
+
capabilities.keyMacro.reason,
|
|
168
|
+
resolvePackages(KEYMACRO_PACKAGES, packageManager),
|
|
169
|
+
packageManager,
|
|
170
|
+
"which ydotool || which wtype || which xdotool",
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (capabilities.clipboard.missing.length > 0 && platform === "linux") {
|
|
176
|
+
const map =
|
|
177
|
+
session === "wayland"
|
|
178
|
+
? CLIPBOARD_WAYLAND_PACKAGES
|
|
179
|
+
: CLIPBOARD_X11_PACKAGES
|
|
180
|
+
steps.push(
|
|
181
|
+
buildCapabilityStep(
|
|
182
|
+
"clipboard",
|
|
183
|
+
session === "wayland" ? "wl-clipboard (wl-copy)" : "xclip",
|
|
184
|
+
capabilities.clipboard.reason,
|
|
185
|
+
resolvePackages(map, packageManager),
|
|
186
|
+
packageManager,
|
|
187
|
+
session === "wayland" ? "which wl-copy" : "which xclip",
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (capabilities.notification.missing.length > 0 && platform === "linux") {
|
|
193
|
+
steps.push(
|
|
194
|
+
buildCapabilityStep(
|
|
195
|
+
"notification",
|
|
196
|
+
"Notification tool (notify-send)",
|
|
197
|
+
capabilities.notification.reason,
|
|
198
|
+
resolvePackages(NOTIFICATION_PACKAGES, packageManager),
|
|
199
|
+
packageManager,
|
|
200
|
+
"which notify-send",
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (capabilities.activeApp.missing.length > 0 && platform === "linux") {
|
|
206
|
+
if (session === "wayland") {
|
|
207
|
+
steps.push(buildGnomeExtensionStep())
|
|
208
|
+
} else if (session === "x11") {
|
|
209
|
+
steps.push(
|
|
210
|
+
buildCapabilityStep(
|
|
211
|
+
"activeApp",
|
|
212
|
+
"Active-app detection (xdotool, xprop)",
|
|
213
|
+
capabilities.activeApp.reason,
|
|
214
|
+
resolvePackages(ACTIVEAPP_X11_PACKAGES, packageManager),
|
|
215
|
+
packageManager,
|
|
216
|
+
"which xdotool",
|
|
217
|
+
),
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (platform === "linux" && !udev.rulesInstalled) {
|
|
223
|
+
steps.push(buildUdevStep(udev.streamDeckConnected))
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return steps
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const needsConfigSeed = (report: SystemReport): boolean =>
|
|
230
|
+
!report.config.exists
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { probeAll, type ProbeDeps, type SystemReport } from "."
|
|
2
|
+
|
|
3
|
+
let cached: { report: SystemReport; at: number; key: string } | null = null
|
|
4
|
+
const DEFAULT_TTL_MS = 5_000
|
|
5
|
+
|
|
6
|
+
// ponytail: the config path is the one dep that differs between two call sites
|
|
7
|
+
// in the same run — the banner probes the XDG default while the first-run gate
|
|
8
|
+
// probes the explicit --config. Keying on it stops the first probe's
|
|
9
|
+
// "Config: missing" from being replayed to the second.
|
|
10
|
+
const cacheKey = (deps: ProbeDeps): string =>
|
|
11
|
+
`${deps.platform}\u0000${deps.xdgConfigHome}\u0000${deps.configPath ?? ""}`
|
|
12
|
+
|
|
13
|
+
// ponytail: single-slot TTL cache. probeAll runs subprocesses (which, sudo,
|
|
14
|
+
// lsusb, ...); the startup banner and runFirstRunCheckIfNeeded both probe the
|
|
15
|
+
// same machine within ms of each other — caching avoids paying for it twice.
|
|
16
|
+
// Single-slot because a CLI invocation probes one machine. Reset between runs
|
|
17
|
+
// via resetProbeCache() for tests.
|
|
18
|
+
export const probeAllCached = async (
|
|
19
|
+
deps: ProbeDeps,
|
|
20
|
+
ttlMs: number = DEFAULT_TTL_MS,
|
|
21
|
+
): Promise<SystemReport> => {
|
|
22
|
+
const now = Date.now()
|
|
23
|
+
const key = cacheKey(deps)
|
|
24
|
+
if (cached !== null && cached.key === key && now - cached.at < ttlMs) {
|
|
25
|
+
return cached.report
|
|
26
|
+
}
|
|
27
|
+
const report = await probeAll(deps)
|
|
28
|
+
cached = { report, at: now, key }
|
|
29
|
+
return report
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const resetProbeCache = (): void => {
|
|
33
|
+
cached = null
|
|
34
|
+
}
|