@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,434 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
renameSync,
|
|
7
|
+
unlinkSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs"
|
|
10
|
+
import { homedir } from "node:os"
|
|
11
|
+
import { join } from "node:path"
|
|
12
|
+
|
|
13
|
+
import { confirm, isCancel, note } from "@/cli/prompt"
|
|
14
|
+
import { loadConfig } from "@/config/loader"
|
|
15
|
+
import { CLAUDE_HOOK_REGISTRATIONS } from "@/builtin-addons/coding-agents/shared/claude-hook-events"
|
|
16
|
+
import {
|
|
17
|
+
CLAUDE_HOOK_FILENAME,
|
|
18
|
+
CLAUDE_HOOK_MARKER,
|
|
19
|
+
CLAUDE_HOOK_VERSION,
|
|
20
|
+
claudeHookSource,
|
|
21
|
+
} from "@/builtin-addons/coding-agents/hook/script"
|
|
22
|
+
import { applyEdits, modify, parse, type ParseError } from "jsonc-parser"
|
|
23
|
+
|
|
24
|
+
const PLUGIN_FILE = "sirenodeck-agent-state.js"
|
|
25
|
+
const PLUGIN_SPEC = `./plugins/${PLUGIN_FILE}`
|
|
26
|
+
const PLUGIN_MARKER = "SIRENODECK_INTEGRATION_ID=coding-agents-v2"
|
|
27
|
+
|
|
28
|
+
const opencodeConfigDir = (): string =>
|
|
29
|
+
process.env["OPENCODE_CONFIG_DIR"] ??
|
|
30
|
+
join(process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config"), "opencode")
|
|
31
|
+
|
|
32
|
+
const pluginDir = (): string => join(opencodeConfigDir(), "plugins")
|
|
33
|
+
|
|
34
|
+
const opencodeConfigPath = (): string =>
|
|
35
|
+
join(opencodeConfigDir(), "opencode.json")
|
|
36
|
+
|
|
37
|
+
export const opencodePluginPath = (): string => join(pluginDir(), PLUGIN_FILE)
|
|
38
|
+
|
|
39
|
+
export const isCodingAgentsConfigured = (configPath: string): boolean => {
|
|
40
|
+
if (!existsSync(configPath)) return false
|
|
41
|
+
try {
|
|
42
|
+
return JSON.stringify(loadConfig({ configPath }).config).includes(
|
|
43
|
+
"coding-agents:",
|
|
44
|
+
)
|
|
45
|
+
} catch {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const isOpenCodePluginInstalled = (): boolean => {
|
|
51
|
+
try {
|
|
52
|
+
return readFileSync(opencodePluginPath(), "utf8").includes(PLUGIN_MARKER)
|
|
53
|
+
} catch {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const readOpenCodeConfig = (): {
|
|
59
|
+
config: Record<string, unknown>
|
|
60
|
+
text: string
|
|
61
|
+
} | null => {
|
|
62
|
+
const path = opencodeConfigPath()
|
|
63
|
+
if (!existsSync(path)) return { config: {}, text: "{}" }
|
|
64
|
+
try {
|
|
65
|
+
const text = readFileSync(path, "utf8")
|
|
66
|
+
const errors: ParseError[] = []
|
|
67
|
+
const parsed: unknown = parse(text, errors, { allowTrailingComma: true })
|
|
68
|
+
if (errors.length > 0) return null
|
|
69
|
+
return parsed !== null && typeof parsed === "object"
|
|
70
|
+
? { config: parsed as Record<string, unknown>, text }
|
|
71
|
+
: null
|
|
72
|
+
} catch {
|
|
73
|
+
return null
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const pluginSpec = (entry: unknown): unknown =>
|
|
78
|
+
Array.isArray(entry) ? entry[0] : entry
|
|
79
|
+
|
|
80
|
+
export const isOpenCodePluginEnabled = (): boolean => {
|
|
81
|
+
const config = readOpenCodeConfig()
|
|
82
|
+
const plugins = config?.config["plugin"]
|
|
83
|
+
return (
|
|
84
|
+
Array.isArray(plugins) &&
|
|
85
|
+
plugins.some((entry) => pluginSpec(entry) === PLUGIN_SPEC)
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const enableOpenCodePlugin = (): boolean => {
|
|
90
|
+
const config = readOpenCodeConfig()
|
|
91
|
+
if (config === null) return false
|
|
92
|
+
const plugins = Array.isArray(config.config["plugin"])
|
|
93
|
+
? config.config["plugin"]
|
|
94
|
+
: []
|
|
95
|
+
if (!plugins.some((entry) => pluginSpec(entry) === PLUGIN_SPEC)) {
|
|
96
|
+
plugins.push(PLUGIN_SPEC)
|
|
97
|
+
const updated = applyEdits(
|
|
98
|
+
config.text,
|
|
99
|
+
modify(config.text, ["plugin"], plugins, {
|
|
100
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
101
|
+
}),
|
|
102
|
+
)
|
|
103
|
+
const path = opencodeConfigPath()
|
|
104
|
+
mkdirSync(opencodeConfigDir(), { recursive: true, mode: 0o700 })
|
|
105
|
+
writeFileSync(path, updated, {
|
|
106
|
+
encoding: "utf8",
|
|
107
|
+
mode: 0o600,
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
return true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const codingAgentsPluginSource = `// ${PLUGIN_MARKER}
|
|
114
|
+
// Managed by Sireno Deck. Re-running setup replaces this file.
|
|
115
|
+
import { mkdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
116
|
+
import { homedir } from "node:os";
|
|
117
|
+
import { join } from "node:path";
|
|
118
|
+
|
|
119
|
+
const dir = join(process.env.XDG_STATE_HOME || join(homedir(), ".local", "state"), "sirenodeck", "coding-agents");
|
|
120
|
+
const file = join(dir, "opencode-" + process.pid + ".json");
|
|
121
|
+
let currentState = "idle";
|
|
122
|
+
let currentSessionID;
|
|
123
|
+
const write = (state, sessionID) => {
|
|
124
|
+
currentState = state;
|
|
125
|
+
if (sessionID) currentSessionID = sessionID;
|
|
126
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
127
|
+
const tmp = file + ".tmp";
|
|
128
|
+
writeFileSync(tmp, JSON.stringify({ pid: process.pid, cwd: process.cwd(), state: currentState, sessionID: currentSessionID, updatedAt: Date.now() }), { mode: 0o600 });
|
|
129
|
+
renameSync(tmp, file);
|
|
130
|
+
};
|
|
131
|
+
write("idle");
|
|
132
|
+
|
|
133
|
+
export const SirenoDeckAgentStatePlugin = async () => ({
|
|
134
|
+
event: async ({ event }) => {
|
|
135
|
+
const p = event?.properties || {};
|
|
136
|
+
const sessionID = p.sessionID;
|
|
137
|
+
switch (event?.type) {
|
|
138
|
+
case "session.status":
|
|
139
|
+
write(p.status?.type === "idle" ? "idle" : p.status?.type === "retry" ? "waiting" : "running", sessionID);
|
|
140
|
+
break;
|
|
141
|
+
case "session.idle": write("idle", sessionID); break;
|
|
142
|
+
case "permission.asked":
|
|
143
|
+
case "question.asked": write("waiting_for_human", sessionID); break;
|
|
144
|
+
case "session.error": write("error", sessionID); break;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
process.once("exit", () => { try { unlinkSync(file); } catch {} });
|
|
150
|
+
const heartbeat = setInterval(() => write(currentState, currentSessionID), 5000);
|
|
151
|
+
process.once("exit", () => clearInterval(heartbeat));
|
|
152
|
+
`
|
|
153
|
+
|
|
154
|
+
export const installOpenCodePlugin = (): string => {
|
|
155
|
+
const path = opencodePluginPath()
|
|
156
|
+
mkdirSync(pluginDir(), { recursive: true, mode: 0o700 })
|
|
157
|
+
writeFileSync(path, codingAgentsPluginSource, {
|
|
158
|
+
encoding: "utf8",
|
|
159
|
+
mode: 0o600,
|
|
160
|
+
})
|
|
161
|
+
return path
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Claude Code
|
|
166
|
+
//
|
|
167
|
+
// ponytail: OpenCode needs a plugin injected into its own config. Claude Code
|
|
168
|
+
// has first-class hooks, so nothing has to be smuggled in — but its
|
|
169
|
+
// settings.json is a file the user owns and very likely already has hooks in
|
|
170
|
+
// (this machine carries three from other tools). Every edit below is surgical:
|
|
171
|
+
// jsonc-parser at the deepest path, ownership decided by a marker inside our
|
|
172
|
+
// own command string, and anything unmarked is never read, moved or rewritten.
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
const CLAUDE_HOOK_ID = `${CLAUDE_HOOK_MARKER}-v${CLAUDE_HOOK_VERSION}`
|
|
176
|
+
|
|
177
|
+
export const claudeConfigDir = (): string =>
|
|
178
|
+
process.env["CLAUDE_CONFIG_DIR"] ?? join(homedir(), ".claude")
|
|
179
|
+
|
|
180
|
+
export const claudeSettingsPath = (): string =>
|
|
181
|
+
join(claudeConfigDir(), "settings.json")
|
|
182
|
+
|
|
183
|
+
export const claudeHookPath = (): string =>
|
|
184
|
+
join(claudeConfigDir(), "hooks", CLAUDE_HOOK_FILENAME)
|
|
185
|
+
|
|
186
|
+
const claudeHookCommand = (): string =>
|
|
187
|
+
`node ${JSON.stringify(claudeHookPath())} $EVENT # ${CLAUDE_HOOK_ID}`
|
|
188
|
+
|
|
189
|
+
const commandFor = (event: string): string =>
|
|
190
|
+
claudeHookCommand().replace("$EVENT", event)
|
|
191
|
+
|
|
192
|
+
const isOurs = (entry: unknown): boolean => {
|
|
193
|
+
if (entry === null || typeof entry !== "object") return false
|
|
194
|
+
const hooks = (entry as { hooks?: unknown }).hooks
|
|
195
|
+
if (!Array.isArray(hooks)) return false
|
|
196
|
+
return hooks.some((h) => {
|
|
197
|
+
const cmd = (h as { command?: unknown }).command
|
|
198
|
+
return (
|
|
199
|
+
typeof cmd === "string" &&
|
|
200
|
+
(cmd.includes(CLAUDE_HOOK_MARKER) || cmd.includes(CLAUDE_HOOK_FILENAME))
|
|
201
|
+
)
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export const isClaudeHookInstalled = (): boolean => {
|
|
206
|
+
try {
|
|
207
|
+
return readFileSync(claudeHookPath(), "utf8").includes(CLAUDE_HOOK_ID)
|
|
208
|
+
} catch {
|
|
209
|
+
return false
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const installClaudeHook = (): string => {
|
|
214
|
+
const path = claudeHookPath()
|
|
215
|
+
mkdirSync(join(claudeConfigDir(), "hooks"), { recursive: true, mode: 0o700 })
|
|
216
|
+
writeFileSync(path, claudeHookSource, { encoding: "utf8", mode: 0o700 })
|
|
217
|
+
return path
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
interface ClaudeSettings {
|
|
221
|
+
readonly text: string
|
|
222
|
+
readonly config: Record<string, unknown>
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const readClaudeSettings = (): ClaudeSettings | null => {
|
|
226
|
+
const path = claudeSettingsPath()
|
|
227
|
+
let text: string
|
|
228
|
+
try {
|
|
229
|
+
text = readFileSync(path, "utf8")
|
|
230
|
+
} catch {
|
|
231
|
+
// No settings file yet — start from an empty object.
|
|
232
|
+
return { text: "{}", config: {} }
|
|
233
|
+
}
|
|
234
|
+
const errors: ParseError[] = []
|
|
235
|
+
const config = parse(text, errors, {
|
|
236
|
+
allowTrailingComma: true,
|
|
237
|
+
}) as Record<string, unknown>
|
|
238
|
+
// Refuse to touch a file we cannot faithfully re-emit.
|
|
239
|
+
if (errors.length > 0 || config === null || typeof config !== "object") {
|
|
240
|
+
return null
|
|
241
|
+
}
|
|
242
|
+
return { text, config }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const hookEntriesFor = (event: string): unknown => {
|
|
246
|
+
const reg = CLAUDE_HOOK_REGISTRATIONS.find((r) => r.event === event)
|
|
247
|
+
return {
|
|
248
|
+
...(reg?.matcher !== undefined ? { matcher: reg.matcher } : {}),
|
|
249
|
+
hooks: [{ type: "command", command: commandFor(event), timeout: 5 }],
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export const isClaudeHookEnabled = (): boolean => {
|
|
254
|
+
const settings = readClaudeSettings()
|
|
255
|
+
if (settings === null) return false
|
|
256
|
+
const hooks = settings.config["hooks"]
|
|
257
|
+
if (hooks === null || typeof hooks !== "object") return false
|
|
258
|
+
return CLAUDE_HOOK_REGISTRATIONS.every((reg) => {
|
|
259
|
+
const list = (hooks as Record<string, unknown>)[reg.event]
|
|
260
|
+
return Array.isArray(list) && list.some(isOurs)
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const writeClaudeSettings = (text: string): void => {
|
|
265
|
+
const path = claudeSettingsPath()
|
|
266
|
+
mkdirSync(claudeConfigDir(), { recursive: true, mode: 0o700 })
|
|
267
|
+
const tmp = `${path}.sirenodeck.tmp`
|
|
268
|
+
writeFileSync(tmp, text, { encoding: "utf8", mode: 0o600 })
|
|
269
|
+
renameSync(tmp, path)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export const enableClaudeHooks = (): boolean => {
|
|
273
|
+
const settings = readClaudeSettings()
|
|
274
|
+
if (settings === null) return false
|
|
275
|
+
|
|
276
|
+
// One backup, before the first edit we ever make to this file.
|
|
277
|
+
const path = claudeSettingsPath()
|
|
278
|
+
const backup = `${path}.sirenodeck.bak`
|
|
279
|
+
if (existsSync(path) && !existsSync(backup)) {
|
|
280
|
+
try {
|
|
281
|
+
copyFileSync(path, backup)
|
|
282
|
+
} catch {
|
|
283
|
+
// Not fatal — the edits below are still surgical.
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let text = settings.text
|
|
288
|
+
for (const reg of CLAUDE_HOOK_REGISTRATIONS) {
|
|
289
|
+
// Re-parse each round so indices stay correct as the document grows.
|
|
290
|
+
const current = parse(text, [], { allowTrailingComma: true }) as Record<
|
|
291
|
+
string,
|
|
292
|
+
unknown
|
|
293
|
+
>
|
|
294
|
+
const hooks = (current["hooks"] ?? {}) as Record<string, unknown>
|
|
295
|
+
const list = Array.isArray(hooks[reg.event])
|
|
296
|
+
? (hooks[reg.event] as unknown[])
|
|
297
|
+
: []
|
|
298
|
+
const mine = list.findIndex(isOurs)
|
|
299
|
+
// Append at an explicit index, or replace our own entry in place. Sibling
|
|
300
|
+
// entries are never re-serialised, so other tools' hooks survive exactly.
|
|
301
|
+
const index = mine === -1 ? list.length : mine
|
|
302
|
+
text = applyEdits(
|
|
303
|
+
text,
|
|
304
|
+
modify(text, ["hooks", reg.event, index], hookEntriesFor(reg.event), {
|
|
305
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
306
|
+
}),
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
writeClaudeSettings(text)
|
|
310
|
+
return true
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export const removeClaudeHook = (): boolean => {
|
|
314
|
+
const settings = readClaudeSettings()
|
|
315
|
+
if (settings === null) return false
|
|
316
|
+
let text = settings.text
|
|
317
|
+
for (const reg of CLAUDE_HOOK_REGISTRATIONS) {
|
|
318
|
+
const current = parse(text, [], { allowTrailingComma: true }) as Record<
|
|
319
|
+
string,
|
|
320
|
+
unknown
|
|
321
|
+
>
|
|
322
|
+
const hooks = (current["hooks"] ?? {}) as Record<string, unknown>
|
|
323
|
+
const list = Array.isArray(hooks[reg.event])
|
|
324
|
+
? (hooks[reg.event] as unknown[])
|
|
325
|
+
: []
|
|
326
|
+
const kept = list.filter((entry) => !isOurs(entry))
|
|
327
|
+
if (kept.length === list.length) continue
|
|
328
|
+
text = applyEdits(
|
|
329
|
+
text,
|
|
330
|
+
modify(text, ["hooks", reg.event], kept.length > 0 ? kept : undefined, {
|
|
331
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
332
|
+
}),
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
writeClaudeSettings(text)
|
|
336
|
+
try {
|
|
337
|
+
unlinkSync(claudeHookPath())
|
|
338
|
+
} catch {
|
|
339
|
+
// Already gone.
|
|
340
|
+
}
|
|
341
|
+
return true
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const onboardClaudeCode = async (options: {
|
|
345
|
+
readonly yes?: boolean
|
|
346
|
+
}): Promise<boolean> => {
|
|
347
|
+
if (isClaudeHookInstalled() && isClaudeHookEnabled()) return false
|
|
348
|
+
note(
|
|
349
|
+
"The coding-agents addon can show each Claude Code session and its live state.\n\n" +
|
|
350
|
+
"Sireno Deck will add hooks to your Claude Code settings. They report only local session state (id, directory, status) to files owned by your user; no prompts or code are captured. Existing hooks are left untouched.",
|
|
351
|
+
"Claude Code integration",
|
|
352
|
+
)
|
|
353
|
+
const answer =
|
|
354
|
+
options.yes === true
|
|
355
|
+
? true
|
|
356
|
+
: await confirm({
|
|
357
|
+
message: "Add the Claude Code session-state hooks now?",
|
|
358
|
+
initialValue: true,
|
|
359
|
+
})
|
|
360
|
+
if (isCancel(answer) || !answer) return false
|
|
361
|
+
installClaudeHook()
|
|
362
|
+
if (!enableClaudeHooks()) {
|
|
363
|
+
note(
|
|
364
|
+
`Could not update ${claudeSettingsPath()} because it is not valid JSON. Nothing was changed.`,
|
|
365
|
+
"Claude Code integration",
|
|
366
|
+
)
|
|
367
|
+
return false
|
|
368
|
+
}
|
|
369
|
+
note(
|
|
370
|
+
`Installed ${claudeHookPath()}. Hooks apply to sessions started from now on; a backup of your settings is at ${claudeSettingsPath()}.sirenodeck.bak.`,
|
|
371
|
+
"Claude Code integration",
|
|
372
|
+
)
|
|
373
|
+
return true
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export const onboardCodingAgents = async (
|
|
377
|
+
configPath: string,
|
|
378
|
+
options: { readonly nonInteractive?: boolean; readonly yes?: boolean } = {},
|
|
379
|
+
): Promise<boolean> => {
|
|
380
|
+
if (!isCodingAgentsConfigured(configPath)) return false
|
|
381
|
+
// ponytail: this used to bail as soon as OpenCode was set up, which meant a
|
|
382
|
+
// user who had already onboarded OpenCode was never offered the Claude Code
|
|
383
|
+
// hooks at all. The two harnesses are independent; each decides for itself.
|
|
384
|
+
const openCodeDone = isOpenCodePluginInstalled() && isOpenCodePluginEnabled()
|
|
385
|
+
const claudeDone = isClaudeHookInstalled() && isClaudeHookEnabled()
|
|
386
|
+
if (openCodeDone && claudeDone) return false
|
|
387
|
+
// ponytail: with no TTY nobody can answer — @clack's confirm() renders the
|
|
388
|
+
// prompt and then blocks forever on a stdin that will never produce a
|
|
389
|
+
// keypress. `start` calls this BEFORE spawning the daemon, so a piped or
|
|
390
|
+
// redirected stdin (CI, a wrapper script, `| tee`) hung the whole start and
|
|
391
|
+
// surfaced as "port 52937 did not accept connections in 30s" — a daemon that
|
|
392
|
+
// was never launched. runFirstRunCheckIfNeeded already guards this way;
|
|
393
|
+
// keep the check here so every caller inherits it.
|
|
394
|
+
if (options.nonInteractive === true || process.stdin.isTTY !== true) {
|
|
395
|
+
return false
|
|
396
|
+
}
|
|
397
|
+
let changed = false
|
|
398
|
+
|
|
399
|
+
if (!openCodeDone) {
|
|
400
|
+
note(
|
|
401
|
+
"The coding-agents addon can show each OpenCode terminal instance and its live state.\n\n" +
|
|
402
|
+
"Sireno Deck will install a global OpenCode plugin. It reports only local process state to files owned by your user; no prompts or code are captured.",
|
|
403
|
+
"OpenCode integration",
|
|
404
|
+
)
|
|
405
|
+
const answer =
|
|
406
|
+
options.yes === true
|
|
407
|
+
? true
|
|
408
|
+
: await confirm({
|
|
409
|
+
message: "Install the OpenCode instance-state plugin now?",
|
|
410
|
+
initialValue: true,
|
|
411
|
+
})
|
|
412
|
+
if (!isCancel(answer) && answer) {
|
|
413
|
+
installOpenCodePlugin()
|
|
414
|
+
if (enableOpenCodePlugin()) {
|
|
415
|
+
note(
|
|
416
|
+
`Installed and enabled ${opencodePluginPath()}. Restart OpenCode to activate it.`,
|
|
417
|
+
"OpenCode integration",
|
|
418
|
+
)
|
|
419
|
+
changed = true
|
|
420
|
+
} else {
|
|
421
|
+
note(
|
|
422
|
+
"Could not update OpenCode's opencode.json because it is invalid JSON.",
|
|
423
|
+
"OpenCode integration",
|
|
424
|
+
)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!claudeDone) {
|
|
430
|
+
changed = (await onboardClaudeCode(options)) || changed
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return changed
|
|
434
|
+
}
|