@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,343 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url"
|
|
2
|
+
import { createRequire } from "node:module"
|
|
3
|
+
import { dirname, resolve as resolvePath, join } from "node:path"
|
|
4
|
+
import { cpSync, existsSync, readFileSync, readdirSync } from "node:fs"
|
|
5
|
+
|
|
6
|
+
import type { AddonRegistry } from "@/addon/registry"
|
|
7
|
+
import type { LoadedTheme } from "@/addon/api"
|
|
8
|
+
import { ThemeJsonManifestSchema, type ThemeJsonManifest } from "./manifest"
|
|
9
|
+
import { buildThemeCss } from "./css"
|
|
10
|
+
import type { ThemeEntry } from "@/config/schemas"
|
|
11
|
+
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
|
|
14
|
+
// ponytail: `here` is the themes dir when running from source
|
|
15
|
+
// (`packages/cli/src/themes`) but the BUNDLE dir when running from dist
|
|
16
|
+
// (`packages/cli/dist`), where the source tree isn't shipped. The dist build
|
|
17
|
+
// sits one level below src/, so try the sibling src/themes fallback first —
|
|
18
|
+
// this is what let the systemd unit (dist) crash on `theme: default` with
|
|
19
|
+
// "not a registered theme". Each candidate is validated by the presence of
|
|
20
|
+
// the `default` theme manifest so a stale candidate can never win.
|
|
21
|
+
const resolveThemesRoot = (): string => {
|
|
22
|
+
const candidates = [
|
|
23
|
+
here,
|
|
24
|
+
resolvePath(here, "..", "src", "themes"),
|
|
25
|
+
resolvePath(here, "..", "..", "src", "themes"),
|
|
26
|
+
]
|
|
27
|
+
for (const candidate of candidates) {
|
|
28
|
+
if (existsSync(join(candidate, "default", "sirenodeck.json"))) {
|
|
29
|
+
return candidate
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return here
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const themesRoot = resolveThemesRoot()
|
|
36
|
+
|
|
37
|
+
// ponytail: sibling scan — first-party themes shipped outside the CLI package
|
|
38
|
+
// (e.g. packages/themes/<name>) get registered as "sibling" so authors can
|
|
39
|
+
// iterate on a theme in a separate workspace. From source `here` is
|
|
40
|
+
// `<repo>/packages/cli/src/themes`, so `../../../themes` lands in
|
|
41
|
+
// `<repo>/packages/themes`; from dist it's `<repo>/packages/cli/dist`, so
|
|
42
|
+
// `../../themes` lands there instead.
|
|
43
|
+
const siblingCandidates = [
|
|
44
|
+
resolvePath(themesRoot, "..", "..", "..", "themes"),
|
|
45
|
+
resolvePath(themesRoot, "..", "..", "themes"),
|
|
46
|
+
]
|
|
47
|
+
const siblingThemesRoot =
|
|
48
|
+
siblingCandidates.find((root) => existsSync(root)) ?? siblingCandidates[0]!
|
|
49
|
+
|
|
50
|
+
export interface BuiltInThemeSpec {
|
|
51
|
+
name: string
|
|
52
|
+
dir: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function _discoverThemesInRoot(
|
|
56
|
+
root: string,
|
|
57
|
+
): ReadonlyArray<{ dir: string; name: string }> {
|
|
58
|
+
if (!existsSync(root)) return []
|
|
59
|
+
const entries = readdirSync(root, { withFileTypes: true })
|
|
60
|
+
const themes: { dir: string; name: string }[] = []
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
if (!entry.isDirectory()) continue
|
|
63
|
+
const manifestPath = join(root, entry.name, "sirenodeck.json")
|
|
64
|
+
if (!existsSync(manifestPath)) continue
|
|
65
|
+
themes.push({ dir: join(root, entry.name), name: entry.name })
|
|
66
|
+
}
|
|
67
|
+
return themes
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function _discoverThemesDir(): ReadonlyArray<{ dir: string; name: string }> {
|
|
71
|
+
return _discoverThemesInRoot(themesRoot)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function _discoverSiblingThemesDir(): ReadonlyArray<{
|
|
75
|
+
dir: string
|
|
76
|
+
name: string
|
|
77
|
+
}> {
|
|
78
|
+
return _discoverThemesInRoot(siblingThemesRoot)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const BUILT_IN_THEMES: ReadonlyArray<BuiltInThemeSpec> =
|
|
82
|
+
_discoverThemesDir().map(({ dir, name }) => ({ name, dir }))
|
|
83
|
+
|
|
84
|
+
function discoverThemeManifests(): ReadonlyArray<{
|
|
85
|
+
dir: string
|
|
86
|
+
name: string
|
|
87
|
+
}> {
|
|
88
|
+
return _discoverThemesDir()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function readAndValidateManifest(
|
|
92
|
+
manifestPath: string,
|
|
93
|
+
expectedName?: string,
|
|
94
|
+
): ThemeJsonManifest {
|
|
95
|
+
let raw: unknown
|
|
96
|
+
try {
|
|
97
|
+
raw = JSON.parse(readFileSync(manifestPath, "utf8"))
|
|
98
|
+
} catch {
|
|
99
|
+
throw new Error(`Failed to parse theme manifest: ${manifestPath}`)
|
|
100
|
+
}
|
|
101
|
+
const result = ThemeJsonManifestSchema.safeParse(raw)
|
|
102
|
+
if (!result.success) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Invalid theme manifest in ${manifestPath}: ${result.error.message}`,
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
if (expectedName !== undefined && result.data.name !== expectedName) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Theme name '${result.data.name}' in ${manifestPath} does not match expected '${expectedName}'`,
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
return result.data
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function buildThemeCssFromManifest(
|
|
116
|
+
manifest: ThemeJsonManifest,
|
|
117
|
+
themeDir: string,
|
|
118
|
+
): string {
|
|
119
|
+
const assetsStyles = (manifest.assets?.styles ?? ["./components.css"]).map(
|
|
120
|
+
(s) => resolvePath(themeDir, s),
|
|
121
|
+
)
|
|
122
|
+
const stylesheetContents = assetsStyles.map((p) => {
|
|
123
|
+
try {
|
|
124
|
+
return readFileSync(p, "utf8")
|
|
125
|
+
} catch {
|
|
126
|
+
return `/* stylesheet not found: ${p} */`
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
return buildThemeCss(manifest, stylesheetContents)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ponytail: theme.css is emitted into the vite frontend's `.sirenodeck/`
|
|
133
|
+
// dir, but its `url('./assets/...')` font/asset paths are relative to THAT
|
|
134
|
+
// file — so the theme's assets/ must be copied next to it or every font 404s.
|
|
135
|
+
export function copyThemeAssets(themeDir: string, cssDir: string): void {
|
|
136
|
+
const assetsDir = join(themeDir, "assets")
|
|
137
|
+
if (!existsSync(assetsDir)) return
|
|
138
|
+
cpSync(assetsDir, join(cssDir, "assets"), { recursive: true })
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function buildLoadedTheme(
|
|
142
|
+
manifest: ThemeJsonManifest,
|
|
143
|
+
themeDir: string,
|
|
144
|
+
source:
|
|
145
|
+
| { kind: "builtin"; resolvedPath: string }
|
|
146
|
+
| { kind: "sibling"; resolvedPath: string }
|
|
147
|
+
| { kind: "local"; resolvedPath: string },
|
|
148
|
+
): { theme: LoadedTheme; getCss: () => string } {
|
|
149
|
+
const uiOverridesPath = manifest["ui-overrides"]
|
|
150
|
+
? resolvePath(themeDir, manifest["ui-overrides"])
|
|
151
|
+
: null
|
|
152
|
+
|
|
153
|
+
const theme: LoadedTheme = {
|
|
154
|
+
name: manifest.name,
|
|
155
|
+
apiVersion: manifest.apiVersion,
|
|
156
|
+
source,
|
|
157
|
+
manifestPath: join(themeDir, "sirenodeck.json"),
|
|
158
|
+
uiOverridesPath,
|
|
159
|
+
cssPath: "",
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const getCss = (): string => buildThemeCssFromManifest(manifest, themeDir)
|
|
163
|
+
|
|
164
|
+
return { theme, getCss }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function loadBuiltInThemes(): Array<{
|
|
168
|
+
theme: LoadedTheme
|
|
169
|
+
getCss: () => string
|
|
170
|
+
}> {
|
|
171
|
+
const discovered = discoverThemeManifests()
|
|
172
|
+
return discovered.map(({ dir, name }) => {
|
|
173
|
+
const manifest = readAndValidateManifest(join(dir, "sirenodeck.json"), name)
|
|
174
|
+
return buildLoadedTheme(manifest, dir, {
|
|
175
|
+
kind: "builtin",
|
|
176
|
+
resolvedPath: dir,
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export const registerBuiltInThemes = (registry: AddonRegistry): void => {
|
|
182
|
+
const builtIns = loadBuiltInThemes()
|
|
183
|
+
for (const { theme } of builtIns) {
|
|
184
|
+
registry.loadTheme(theme)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function loadSiblingThemes(): Array<{
|
|
189
|
+
theme: LoadedTheme
|
|
190
|
+
getCss: () => string
|
|
191
|
+
}> {
|
|
192
|
+
const discovered = _discoverSiblingThemesDir()
|
|
193
|
+
return discovered.map(({ dir, name }) => {
|
|
194
|
+
const manifest = readAndValidateManifest(join(dir, "sirenodeck.json"), name)
|
|
195
|
+
return buildLoadedTheme(manifest, dir, {
|
|
196
|
+
kind: "sibling",
|
|
197
|
+
resolvedPath: dir,
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export const registerSiblingThemes = (registry: AddonRegistry): void => {
|
|
203
|
+
const siblings = loadSiblingThemes()
|
|
204
|
+
for (const { theme } of siblings) {
|
|
205
|
+
registry.loadTheme(theme)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function loadThemeFromPath(
|
|
210
|
+
registry: AddonRegistry,
|
|
211
|
+
themePath: string,
|
|
212
|
+
aliasName?: string,
|
|
213
|
+
): { theme: LoadedTheme; getCss: () => string } {
|
|
214
|
+
const resolvedPath = resolvePath(themePath)
|
|
215
|
+
const manifestPath = join(resolvedPath, "sirenodeck.json")
|
|
216
|
+
const manifest = readAndValidateManifest(manifestPath)
|
|
217
|
+
const { theme, getCss } = buildLoadedTheme(manifest, resolvedPath, {
|
|
218
|
+
kind: "local",
|
|
219
|
+
resolvedPath,
|
|
220
|
+
})
|
|
221
|
+
// ponytail: theme may already be registered by `registerSiblingThemes`
|
|
222
|
+
// (sibling scan at boot) or a previous load. Skip the duplicate-registration
|
|
223
|
+
// throw — the manifest-driven getCss callback is still produced either way.
|
|
224
|
+
if (registry.getTheme(theme.name) === undefined) {
|
|
225
|
+
registry.loadTheme(theme)
|
|
226
|
+
}
|
|
227
|
+
if (aliasName !== undefined && aliasName !== manifest.name) {
|
|
228
|
+
if (registry.getTheme(aliasName) === undefined) {
|
|
229
|
+
registry.loadTheme({ ...theme, name: aliasName })
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return { theme, getCss }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export type ResolveThemeOptions = {
|
|
236
|
+
theme: ThemeEntry | undefined
|
|
237
|
+
packageRoots?: ReadonlyArray<string>
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface ResolveThemeResult {
|
|
241
|
+
theme: LoadedTheme
|
|
242
|
+
getCss: () => string
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Detect whether a string looks like a filesystem path. Strict prefix
|
|
247
|
+
* detection — only `./`, `../`, `/`, or a Windows drive letter. Anything
|
|
248
|
+
* else is treated as a registered theme name or an npm package.
|
|
249
|
+
*/
|
|
250
|
+
function isPathLike(s: string): boolean {
|
|
251
|
+
return (
|
|
252
|
+
s.startsWith("./") ||
|
|
253
|
+
s.startsWith("../") ||
|
|
254
|
+
s.startsWith("/") ||
|
|
255
|
+
/^[a-zA-Z]:[\\/]/.test(s)
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Resolve an npm package name to its installed directory via Node's
|
|
261
|
+
* resolver. Returns null when the package isn't found.
|
|
262
|
+
*/
|
|
263
|
+
function resolvePackagePath(
|
|
264
|
+
name: string,
|
|
265
|
+
packageRoots: ReadonlyArray<string> = [],
|
|
266
|
+
): string | null {
|
|
267
|
+
try {
|
|
268
|
+
const require = createRequire(import.meta.url)
|
|
269
|
+
const pkgJsonPath = require.resolve(`${name}/package.json`)
|
|
270
|
+
return dirname(pkgJsonPath)
|
|
271
|
+
} catch {
|
|
272
|
+
for (const root of packageRoots) {
|
|
273
|
+
const candidate = join(root, name)
|
|
274
|
+
if (existsSync(join(candidate, "package.json"))) return candidate
|
|
275
|
+
}
|
|
276
|
+
return null
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const resolveBuiltinTheme = (
|
|
281
|
+
registry: AddonRegistry,
|
|
282
|
+
theme: LoadedTheme,
|
|
283
|
+
): ResolveThemeResult => {
|
|
284
|
+
if (theme.source.kind === "builtin" || theme.source.kind === "sibling") {
|
|
285
|
+
const themeDir = dirname(theme.manifestPath)
|
|
286
|
+
const manifest = readAndValidateManifest(theme.manifestPath, theme.name)
|
|
287
|
+
return {
|
|
288
|
+
theme,
|
|
289
|
+
getCss: () => buildThemeCssFromManifest(manifest, themeDir),
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return { theme, getCss: () => "" }
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const resolveStringTheme = (
|
|
296
|
+
entry: string,
|
|
297
|
+
registry: AddonRegistry,
|
|
298
|
+
packageRoots: ReadonlyArray<string>,
|
|
299
|
+
): ResolveThemeResult => {
|
|
300
|
+
// 1. Registered theme name (built-in auto-discovery or a previously
|
|
301
|
+
// loaded theme). Use getTheme (returns undefined when missing);
|
|
302
|
+
// resolveActiveTheme throws, which short-circuits the dispatcher.
|
|
303
|
+
const registered = registry.getTheme(entry)
|
|
304
|
+
if (registered) {
|
|
305
|
+
return resolveBuiltinTheme(registry, registered)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// 2. Path — `./`, `../`, `/`, or a Windows drive letter.
|
|
309
|
+
if (isPathLike(entry)) {
|
|
310
|
+
return loadThemeFromPath(registry, entry)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// 3. npm package — resolve to the installed package directory and load
|
|
314
|
+
// the theme files inside it.
|
|
315
|
+
const packagePath = resolvePackagePath(entry, packageRoots)
|
|
316
|
+
if (packagePath !== null) {
|
|
317
|
+
return loadThemeFromPath(registry, packagePath)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
throw new Error(
|
|
321
|
+
`Theme '${entry}' is not a registered theme, not a path, and not a known npm package.`,
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export const resolveActiveTheme = (
|
|
326
|
+
registry: AddonRegistry,
|
|
327
|
+
options: ResolveThemeOptions,
|
|
328
|
+
): ResolveThemeResult => {
|
|
329
|
+
const { theme: themeEntry } = options
|
|
330
|
+
if (themeEntry === undefined) {
|
|
331
|
+
const theme = registry.resolveActiveTheme(undefined)
|
|
332
|
+
return resolveBuiltinTheme(registry, theme)
|
|
333
|
+
}
|
|
334
|
+
if (typeof themeEntry === "object") {
|
|
335
|
+
const resolved = resolvePackagePath(themeEntry.src, options.packageRoots)
|
|
336
|
+
if (resolved === null)
|
|
337
|
+
throw new Error(
|
|
338
|
+
`Theme '${themeEntry.src}' is not installed. Run 'sirenodeck install ${themeEntry.src}'.`,
|
|
339
|
+
)
|
|
340
|
+
return loadThemeFromPath(registry, resolved)
|
|
341
|
+
}
|
|
342
|
+
return resolveStringTheme(themeEntry, registry, options.packageRoots ?? [])
|
|
343
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { z } from "zod"
|
|
2
|
+
|
|
3
|
+
export const ThemeColorTokenSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
background: z.string().min(1),
|
|
6
|
+
frame: z.string().min(1),
|
|
7
|
+
foreground: z.string().min(1),
|
|
8
|
+
"foreground-contrast": z.string().min(1),
|
|
9
|
+
primary: z.string().min(1),
|
|
10
|
+
accent: z.string().min(1),
|
|
11
|
+
muted: z.string().min(1).optional(),
|
|
12
|
+
success: z.string().min(1),
|
|
13
|
+
danger: z.string().min(1),
|
|
14
|
+
})
|
|
15
|
+
.strict()
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Required variant keys every theme must declare. Addons can rely on these
|
|
19
|
+
* five for highlights, warnings, success and error states without falling
|
|
20
|
+
* back to a hardcoded palette.
|
|
21
|
+
*
|
|
22
|
+
* Themes may declare EXTRA variants on top — those surface as `--sireno-variant-<name>-*`
|
|
23
|
+
* CSS vars and become available to user config.
|
|
24
|
+
*/
|
|
25
|
+
export const REQUIRED_VARIANT_KEYS = ["default", "error"] as const
|
|
26
|
+
|
|
27
|
+
export type RequiredVariantKey = (typeof REQUIRED_VARIANT_KEYS)[number]
|
|
28
|
+
|
|
29
|
+
const ThemeVariantTokenOverridesSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
primary: z.string().min(1).optional(),
|
|
32
|
+
accent: z.string().min(1).optional(),
|
|
33
|
+
foreground: z.string().min(1).optional(),
|
|
34
|
+
"foreground-contrast": z.string().min(1).optional(),
|
|
35
|
+
success: z.string().min(1).optional(),
|
|
36
|
+
danger: z.string().min(1).optional(),
|
|
37
|
+
muted: z.string().min(1).optional(),
|
|
38
|
+
})
|
|
39
|
+
.strict()
|
|
40
|
+
|
|
41
|
+
export const ThemeVariantStylesSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
background: z.string().min(1),
|
|
44
|
+
border: z.string().min(1),
|
|
45
|
+
foreground: z.string().min(1),
|
|
46
|
+
glow: z.string().optional(),
|
|
47
|
+
tokens: ThemeVariantTokenOverridesSchema.optional(),
|
|
48
|
+
})
|
|
49
|
+
.strict()
|
|
50
|
+
|
|
51
|
+
export const ThemeVariantsSchema = z
|
|
52
|
+
.record(z.string().min(1), ThemeVariantStylesSchema)
|
|
53
|
+
.superRefine((variants, ctx) => {
|
|
54
|
+
const missing = REQUIRED_VARIANT_KEYS.filter((k) => !(k in variants))
|
|
55
|
+
if (missing.length === 0) return
|
|
56
|
+
for (const key of missing) {
|
|
57
|
+
ctx.addIssue({
|
|
58
|
+
code: z.ZodIssueCode.custom,
|
|
59
|
+
path: [key],
|
|
60
|
+
message: `theme manifest is missing required variant "${key}" — every theme must declare variants: { ${REQUIRED_VARIANT_KEYS.map((k) => `"${k}"`).join(", ")} } at minimum`,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
export const ThemeTypographyRoleSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
fontFamily: z.string().min(1),
|
|
68
|
+
fontSize: z.number().positive(),
|
|
69
|
+
fontWeight: z.number().int().positive(),
|
|
70
|
+
letterSpacing: z.number().optional(),
|
|
71
|
+
})
|
|
72
|
+
.strict()
|
|
73
|
+
|
|
74
|
+
export const ThemeTypographySchema = z
|
|
75
|
+
.object({
|
|
76
|
+
main_text: ThemeTypographyRoleSchema,
|
|
77
|
+
auxiliary_text: ThemeTypographyRoleSchema,
|
|
78
|
+
monospace: ThemeTypographyRoleSchema,
|
|
79
|
+
})
|
|
80
|
+
.strict()
|
|
81
|
+
|
|
82
|
+
export const ThemeFontFaceSchema = z
|
|
83
|
+
.object({
|
|
84
|
+
fontFamily: z.string().min(1),
|
|
85
|
+
fontWeight: z.number().int().positive(),
|
|
86
|
+
fontStyle: z.enum(["normal", "italic", "oblique"]).default("normal"),
|
|
87
|
+
src: z.string().min(1),
|
|
88
|
+
/**
|
|
89
|
+
* Optional variable-font axes — accepts a [min, max] tuple per axis.
|
|
90
|
+
* When set, css.ts emits a single @font-face with `font-weight: from..to`
|
|
91
|
+
* shorthand so one entry can serve a range without duplicating files.
|
|
92
|
+
*/
|
|
93
|
+
axes: z
|
|
94
|
+
.object({
|
|
95
|
+
weight: z.tuple([z.number().int(), z.number().int()]).optional(),
|
|
96
|
+
slant: z.tuple([z.number(), z.number()]).optional(),
|
|
97
|
+
width: z.tuple([z.number(), z.number()]).optional(),
|
|
98
|
+
})
|
|
99
|
+
.optional(),
|
|
100
|
+
})
|
|
101
|
+
.strict()
|
|
102
|
+
|
|
103
|
+
export const ThemeEffectsSchema = z
|
|
104
|
+
.object({
|
|
105
|
+
glow: z
|
|
106
|
+
.object({
|
|
107
|
+
sm: z.string().min(1),
|
|
108
|
+
md: z.string().min(1),
|
|
109
|
+
lg: z.string().min(1),
|
|
110
|
+
})
|
|
111
|
+
.partial()
|
|
112
|
+
.optional(),
|
|
113
|
+
shadow: z
|
|
114
|
+
.object({
|
|
115
|
+
soft: z.string().min(1),
|
|
116
|
+
hard: z.string().min(1),
|
|
117
|
+
})
|
|
118
|
+
.partial()
|
|
119
|
+
.optional(),
|
|
120
|
+
blur: z
|
|
121
|
+
.object({
|
|
122
|
+
sm: z.string().min(1),
|
|
123
|
+
md: z.string().min(1),
|
|
124
|
+
})
|
|
125
|
+
.partial()
|
|
126
|
+
.optional(),
|
|
127
|
+
})
|
|
128
|
+
.strict()
|
|
129
|
+
.optional()
|
|
130
|
+
|
|
131
|
+
export const ThemeAssetsSchema = z
|
|
132
|
+
.object({
|
|
133
|
+
styles: z.array(z.string().min(1)).default([]),
|
|
134
|
+
})
|
|
135
|
+
.strict()
|
|
136
|
+
|
|
137
|
+
export const ThemeJsonManifestSchema = z
|
|
138
|
+
.object({
|
|
139
|
+
kind: z.literal("theme"),
|
|
140
|
+
apiVersion: z.number().int().positive(),
|
|
141
|
+
name: z.string().min(1),
|
|
142
|
+
version: z.string().min(1).optional(),
|
|
143
|
+
description: z.string().min(1).optional(),
|
|
144
|
+
colorTokens: ThemeColorTokenSchema,
|
|
145
|
+
typography: ThemeTypographySchema,
|
|
146
|
+
fonts: z.array(ThemeFontFaceSchema).default([]),
|
|
147
|
+
effects: ThemeEffectsSchema,
|
|
148
|
+
variants: ThemeVariantsSchema,
|
|
149
|
+
assets: ThemeAssetsSchema.optional(),
|
|
150
|
+
"ui-overrides": z.string().min(1).optional(),
|
|
151
|
+
})
|
|
152
|
+
.strict()
|
|
153
|
+
|
|
154
|
+
export type ThemeJsonManifest = z.infer<typeof ThemeJsonManifestSchema>
|
|
155
|
+
|
|
156
|
+
export type ThemeColorToken = keyof z.infer<typeof ThemeColorTokenSchema>
|
|
157
|
+
|
|
158
|
+
export type ThemeTypographyRole = keyof z.infer<typeof ThemeTypographySchema>
|
|
159
|
+
|
|
160
|
+
export type ThemeVariantStyles = z.infer<typeof ThemeVariantStylesSchema>
|
|
161
|
+
|
|
162
|
+
export type ThemeVariantName = string
|
|
163
|
+
|
|
164
|
+
export type ThemeVariants = z.infer<typeof ThemeVariantsSchema>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createContext, useContext, type ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import type { LoadedTheme } from "@/addon/api"
|
|
4
|
+
|
|
5
|
+
export interface ThemeContextValue {
|
|
6
|
+
name: string
|
|
7
|
+
cssPath: string
|
|
8
|
+
theme: LoadedTheme
|
|
9
|
+
colorTokens: Record<string, string> | null
|
|
10
|
+
typography: Record<string, unknown> | null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const ThemeContext = createContext<ThemeContextValue | null>(null)
|
|
14
|
+
|
|
15
|
+
export interface ThemeProviderProps {
|
|
16
|
+
value: ThemeContextValue
|
|
17
|
+
children: ReactNode
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ThemeProvider = ({ value, children }: ThemeProviderProps) => (
|
|
21
|
+
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export const useTheme = (): ThemeContextValue => {
|
|
25
|
+
const ctx = useContext(ThemeContext)
|
|
26
|
+
if (!ctx) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"useTheme must be used inside <ThemeProvider>. Ensure your app is wrapped in ThemeProvider with a resolved theme.",
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
return ctx
|
|
32
|
+
}
|