@elizaos/ui 2.0.0-alpha.385 → 2.0.0-alpha.392
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/apps/app-companion/src/components/companion/CompanionAppView.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/CompanionAppView.js +6 -4
- package/apps/app-companion/src/components/companion/CompanionView.d.ts.map +1 -1
- package/apps/app-companion/src/components/companion/CompanionView.js +6 -4
- package/apps/app-lifeops/src/api/client-lifeops.js +6 -0
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.d.ts +3 -0
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/AppBlockerSettingsCard.js +189 -0
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.d.ts +2 -0
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/BrowserBridgeSetupPanel.js +1065 -0
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.d.ts +7 -0
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/BrowserBridgeStatusChip.js +71 -0
- package/apps/app-lifeops/src/components/DataSourcesStrip.d.ts +14 -0
- package/apps/app-lifeops/src/components/DataSourcesStrip.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/DataSourcesStrip.js +36 -0
- package/apps/app-lifeops/src/components/EventEditorDrawer.d.ts +23 -0
- package/apps/app-lifeops/src/components/EventEditorDrawer.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/EventEditorDrawer.js +514 -0
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsActivitySignalsEffect.js +10 -0
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.d.ts +15 -0
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsCalendarSection.js +515 -0
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.d.ts +34 -0
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsChatAdapter.js +175 -0
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsFeatureTogglesSection.js +99 -0
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.d.ts +37 -0
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsHabitVisuals.js +88 -0
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.d.ts +13 -0
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsInboxSection.js +490 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.d.ts +12 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkBankButton.js +92 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.d.ts +12 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsLinkPaypalButton.js +160 -0
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.d.ts +3 -0
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsMoneySection.js +373 -0
- package/apps/app-lifeops/src/components/LifeOpsNavRail.d.ts +9 -0
- package/apps/app-lifeops/src/components/LifeOpsNavRail.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsNavRail.js +93 -0
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.d.ts +4 -0
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsOperationalPanels.js +274 -0
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.d.ts +7 -0
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsOverviewSection.js +657 -0
- package/apps/app-lifeops/src/components/LifeOpsPageSections.d.ts +42 -0
- package/apps/app-lifeops/src/components/LifeOpsPageSections.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsPageSections.js +166 -0
- package/apps/app-lifeops/src/components/LifeOpsPageView.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsPageView.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsPageView.js +566 -0
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsRemindersSection.js +749 -0
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.d.ts +27 -0
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsResizableSidebar.js +106 -0
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsScreenTimeSection.js +373 -0
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.d.ts +10 -0
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSectionContent.js +30 -0
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.d.ts +21 -0
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSelectionContext.js +30 -0
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.d.ts +20 -0
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSettingsSection.js +597 -0
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.d.ts +13 -0
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSetupGate.js +134 -0
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.d.ts +10 -0
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsSleepSection.js +425 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.d.ts +11 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceShell.js +49 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.d.ts +2 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/LifeOpsWorkspaceView.js +1041 -0
- package/apps/app-lifeops/src/components/MessagingConnectorCards.d.ts +7 -0
- package/apps/app-lifeops/src/components/MessagingConnectorCards.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/MessagingConnectorCards.js +643 -0
- package/apps/app-lifeops/src/components/MissingSourceCard.d.ts +9 -0
- package/apps/app-lifeops/src/components/MissingSourceCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/MissingSourceCard.js +5 -0
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.d.ts +2 -0
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/MobileSignalsSetupCard.js +163 -0
- package/apps/app-lifeops/src/components/SleepInspectionPanel.d.ts +8 -0
- package/apps/app-lifeops/src/components/SleepInspectionPanel.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/SleepInspectionPanel.js +59 -0
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.d.ts +3 -0
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/WebsiteBlockerSettingsCard.js +75 -0
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.d.ts +8 -0
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/WhatsAppQrOverlay.js +48 -0
- package/apps/app-lifeops/src/components/lifeops-labels.d.ts +2 -0
- package/apps/app-lifeops/src/components/lifeops-labels.d.ts.map +1 -0
- package/apps/app-lifeops/src/components/lifeops-labels.js +5 -0
- package/apps/app-lifeops/src/events/index.d.ts +34 -0
- package/apps/app-lifeops/src/events/index.d.ts.map +1 -0
- package/apps/app-lifeops/src/events/index.js +23 -0
- package/apps/app-lifeops/src/hooks/useCalendarWeek.d.ts +28 -0
- package/apps/app-lifeops/src/hooks/useCalendarWeek.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useCalendarWeek.js +93 -0
- package/apps/app-lifeops/src/hooks/useDiscordConnector.d.ts +14 -0
- package/apps/app-lifeops/src/hooks/useDiscordConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useDiscordConnector.js +126 -0
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.d.ts +29 -0
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useGoogleLifeOpsConnector.js +481 -0
- package/apps/app-lifeops/src/hooks/useIMessageConnector.d.ts +10 -0
- package/apps/app-lifeops/src/hooks/useIMessageConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useIMessageConnector.js +50 -0
- package/apps/app-lifeops/src/hooks/useInbox.d.ts +34 -0
- package/apps/app-lifeops/src/hooks/useInbox.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useInbox.js +98 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.d.ts +2 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsActivitySignals.js +383 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.d.ts +9 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsAppState.js +83 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.d.ts +8 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsCapabilitiesStatus.js +60 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.d.ts +18 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleInspection.js +66 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.d.ts +14 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsScheduleState.js +79 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.d.ts +18 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsSection.js +78 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.d.ts +14 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useLifeOpsXConnector.js +160 -0
- package/apps/app-lifeops/src/hooks/useSignalConnector.d.ts +16 -0
- package/apps/app-lifeops/src/hooks/useSignalConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useSignalConnector.js +198 -0
- package/apps/app-lifeops/src/hooks/useTelegramConnector.d.ts +21 -0
- package/apps/app-lifeops/src/hooks/useTelegramConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useTelegramConnector.js +177 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.d.ts +8 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppConnector.js +58 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.d.ts +12 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.d.ts.map +1 -0
- package/apps/app-lifeops/src/hooks/useWhatsAppPairing.js +152 -0
- package/apps/app-lifeops/src/lifeops/discord-browser-scraper.js +1 -1
- package/apps/app-lifeops/src/lifeops/google-gmail.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-gmail.js +74 -26
- package/apps/app-lifeops/src/lifeops/google-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-managed-client.js +4 -5
- package/apps/app-lifeops/src/lifeops/google-oauth.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/google-oauth.js +2 -2
- package/apps/app-lifeops/src/lifeops/owner-profile.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/owner-profile.js +1 -1
- package/apps/app-lifeops/src/lifeops/paypal-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/paypal-managed-client.js +4 -5
- package/apps/app-lifeops/src/lifeops/plaid-managed-client.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/plaid-managed-client.js +4 -5
- package/apps/app-lifeops/src/lifeops/schedule-sync-client.js +2 -2
- package/apps/app-lifeops/src/lifeops/service-constants.d.ts +1 -0
- package/apps/app-lifeops/src/lifeops/service-constants.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-constants.js +1 -0
- package/apps/app-lifeops/src/lifeops/service-mixin-core.d.ts +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-core.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-core.js +2 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-imessage.js +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.d.ts +3 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-inbox.js +42 -13
- package/apps/app-lifeops/src/lifeops/service-mixin-reminders.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-reminders.js +3 -2
- package/apps/app-lifeops/src/lifeops/service-mixin-workflows.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-mixin-workflows.js +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-calendar.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-calendar.js +3 -3
- package/apps/app-lifeops/src/lifeops/service-normalize-connector.d.ts +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-connector.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/service-normalize-connector.js +2 -2
- package/apps/app-lifeops/src/lifeops/signal-auth.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/signal-auth.js +6 -3
- package/apps/app-lifeops/src/lifeops/telegram-auth.js +1 -1
- package/apps/app-lifeops/src/lifeops/travel-adapters/duffel.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/travel-adapters/duffel.js +31 -6
- package/apps/app-lifeops/src/lifeops/twilio.js +1 -1
- package/apps/app-lifeops/src/lifeops/x-poster.d.ts.map +1 -1
- package/apps/app-lifeops/src/lifeops/x-poster.js +13 -3
- package/apps/app-lifeops/src/lifeops-route.d.ts +74 -0
- package/apps/app-lifeops/src/lifeops-route.d.ts.map +1 -0
- package/apps/app-lifeops/src/lifeops-route.js +204 -0
- package/apps/app-lifeops/src/platform/lifeops-github.d.ts +15 -0
- package/apps/app-lifeops/src/platform/lifeops-github.d.ts.map +1 -0
- package/apps/app-lifeops/src/platform/lifeops-github.js +135 -0
- package/apps/app-lifeops/src/routes/cloud-features-routes.d.ts +2 -2
- package/apps/app-lifeops/src/routes/cloud-features-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/cloud-features-routes.js +5 -3
- package/apps/app-lifeops/src/routes/lifeops-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/lifeops-routes.js +15 -3
- package/apps/app-lifeops/src/routes/plugin.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/plugin.js +10 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.d.ts +1 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/routes/travel-provider-relay-routes.js +4 -2
- package/apps/app-lifeops/src/routes/website-blocker-routes.d.ts +1 -1
- package/apps/app-lifeops/src/routes/website-blocker-routes.d.ts.map +1 -1
- package/apps/app-lifeops/src/ui.d.ts +11 -0
- package/apps/app-lifeops/src/ui.d.ts.map +1 -0
- package/apps/app-lifeops/src/ui.js +9 -0
- package/apps/app-lifeops/src/utils/lifeops-url.d.ts +5 -0
- package/apps/app-lifeops/src/utils/lifeops-url.d.ts.map +1 -0
- package/apps/app-lifeops/src/utils/lifeops-url.js +35 -0
- package/apps/app-lifeops/src/website-blocker/access.d.ts.map +1 -1
- package/apps/app-lifeops/src/website-blocker/access.js +1 -1
- package/apps/app-steward/src/routes/steward-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/steward-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/steward-compat-routes.js +3 -1
- package/apps/app-steward/src/routes/wallet-browser-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/wallet-browser-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-browser-compat-routes.js +3 -1
- package/apps/app-steward/src/routes/wallet-bsc-core-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-bsc-core-routes.js +2 -1
- package/apps/app-steward/src/routes/wallet-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/wallet-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-compat-routes.js +3 -1
- package/apps/app-steward/src/routes/wallet-core-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-core-routes.js +2 -1
- package/apps/app-steward/src/routes/wallet-trade-compat-routes.d.ts +1 -1
- package/apps/app-steward/src/routes/wallet-trade-compat-routes.d.ts.map +1 -1
- package/apps/app-steward/src/routes/wallet-trade-compat-routes.js +3 -1
- package/apps/app-training/src/core/dataset-generator.d.ts +1 -1
- package/apps/app-training/src/core/dataset-generator.d.ts.map +1 -1
- package/apps/app-training/src/core/roleplay-executor.d.ts +1 -1
- package/apps/app-training/src/core/roleplay-executor.d.ts.map +1 -1
- package/apps/app-training/src/core/trajectory-task-datasets.d.ts +1 -1
- package/apps/app-training/src/core/trajectory-task-datasets.d.ts.map +1 -1
- package/apps/app-training/src/index.d.ts +1 -2
- package/apps/app-training/src/index.d.ts.map +1 -1
- package/apps/app-training/src/index.js +1 -2
- package/apps/app-training/src/routes/training-routes.d.ts +1 -1
- package/apps/app-training/src/routes/training-routes.d.ts.map +1 -1
- package/apps/app-training/src/routes/training-routes.js +1 -1
- package/apps/app-training/src/routes/trajectory-routes.d.ts +1 -1
- package/apps/app-training/src/routes/trajectory-routes.d.ts.map +1 -1
- package/apps/app-training/src/routes/trajectory-routes.js +3 -1
- package/apps/app-training/src/services/training-service-like.d.ts +1 -1
- package/apps/app-training/src/services/training-service-like.d.ts.map +1 -1
- package/apps/app-training/src/services/training-service.d.ts +1 -1
- package/apps/app-training/src/services/training-service.d.ts.map +1 -1
- package/package.json +1 -1
- package/packages/agent/src/api/provider-switch-config.js +1 -1
- package/packages/agent/src/api/server-helpers-auth.d.ts.map +1 -1
- package/packages/agent/src/api/server-helpers-auth.js +5 -4
- package/packages/agent/src/providers/media-provider.d.ts +1 -1
- package/packages/agent/src/providers/media-provider.d.ts.map +1 -1
- package/packages/app-core/src/App.d.ts.map +1 -1
- package/packages/app-core/src/App.js +20 -12
- package/packages/app-core/src/api/auth.d.ts.map +1 -1
- package/packages/app-core/src/api/auth.js +5 -5
- package/packages/app-core/src/api/client-types-experience.d.ts +7 -0
- package/packages/app-core/src/api/client-types-experience.d.ts.map +1 -1
- package/packages/app-core/src/components/apps/helpers.d.ts +1 -1
- package/packages/app-core/src/components/apps/helpers.d.ts.map +1 -1
- package/packages/app-core/src/components/apps/helpers.js +1 -0
- package/packages/app-core/src/components/apps/internal-tool-apps.d.ts +11 -0
- package/packages/app-core/src/components/apps/internal-tool-apps.d.ts.map +1 -1
- package/packages/app-core/src/components/apps/internal-tool-apps.js +31 -0
- package/packages/app-core/src/components/apps/launch-history.d.ts +16 -0
- package/packages/app-core/src/components/apps/launch-history.d.ts.map +1 -0
- package/packages/app-core/src/components/apps/launch-history.js +77 -0
- package/packages/app-core/src/components/apps/per-app-config.d.ts +19 -0
- package/packages/app-core/src/components/apps/per-app-config.d.ts.map +1 -0
- package/packages/app-core/src/components/apps/per-app-config.js +99 -0
- package/packages/app-core/src/components/apps/useRegistryCatalog.d.ts +14 -0
- package/packages/app-core/src/components/apps/useRegistryCatalog.d.ts.map +1 -0
- package/packages/app-core/src/components/apps/useRegistryCatalog.js +52 -0
- package/packages/app-core/src/components/auth/LoginView.d.ts +1 -19
- package/packages/app-core/src/components/auth/LoginView.d.ts.map +1 -1
- package/packages/app-core/src/components/auth/LoginView.js +4 -99
- package/packages/app-core/src/components/character/CharacterExperienceWorkspace.d.ts.map +1 -1
- package/packages/app-core/src/components/character/CharacterExperienceWorkspace.js +14 -2
- package/packages/app-core/src/components/character/character-hub-helpers.d.ts.map +1 -1
- package/packages/app-core/src/components/character/character-hub-helpers.js +7 -0
- package/packages/app-core/src/components/character/character-hub-types.d.ts +7 -0
- package/packages/app-core/src/components/character/character-hub-types.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/BootstrapStep.d.ts.map +1 -1
- package/packages/app-core/src/components/onboarding/BootstrapStep.js +3 -2
- package/packages/app-core/src/components/pages/AppDetailsView.d.ts +36 -0
- package/packages/app-core/src/components/pages/AppDetailsView.d.ts.map +1 -0
- package/packages/app-core/src/components/pages/AppDetailsView.js +289 -0
- package/packages/app-core/src/components/pages/AppsView.d.ts.map +1 -1
- package/packages/app-core/src/components/pages/AppsView.js +134 -42
- package/packages/app-core/src/components/shell/StartupShell.d.ts.map +1 -1
- package/packages/app-core/src/components/shell/StartupShell.js +2 -5
- package/packages/app-core/src/i18n/locales/en.json +256 -205
- package/packages/app-core/src/i18n/locales/es.json +256 -205
- package/packages/app-core/src/i18n/locales/ko.json +256 -205
- package/packages/app-core/src/i18n/locales/pt.json +256 -205
- package/packages/app-core/src/i18n/locales/tl.json +256 -205
- package/packages/app-core/src/i18n/locales/vi.json +256 -205
- package/packages/app-core/src/i18n/locales/zh-CN.json +256 -205
- package/packages/app-core/src/navigation/index.d.ts.map +1 -1
- package/packages/app-core/src/navigation/index.js +6 -0
- package/packages/app-core/src/shell/AppWindowRenderer.d.ts +17 -0
- package/packages/app-core/src/shell/AppWindowRenderer.d.ts.map +1 -0
- package/packages/app-core/src/shell/AppWindowRenderer.js +337 -0
- package/packages/app-core/src/shell/DetachedShellRoot.js +4 -1
- package/packages/app-core/src/shell/index.d.ts +1 -0
- package/packages/app-core/src/shell/index.d.ts.map +1 -1
- package/packages/app-core/src/shell/index.js +1 -0
- package/packages/app-core/src/state/startup-coordinator.d.ts.map +1 -1
- package/packages/app-core/src/state/startup-coordinator.js +0 -3
- package/packages/app-core/src/state/startup-phase-poll.d.ts.map +1 -1
- package/packages/app-core/src/state/startup-phase-poll.js +2 -4
- package/packages/app-core/src/state/usePluginsSkillsState.d.ts +6 -6
- package/packages/native-plugins/mobile-signals/src/definitions.d.ts +162 -0
- package/packages/native-plugins/mobile-signals/src/definitions.d.ts.map +1 -0
- package/packages/native-plugins/mobile-signals/src/definitions.js +1 -0
- package/packages/native-plugins/mobile-signals/src/index.d.ts +4 -0
- package/packages/native-plugins/mobile-signals/src/index.d.ts.map +1 -0
- package/packages/native-plugins/mobile-signals/src/index.js +6 -0
- package/packages/native-plugins/mobile-signals/src/web.d.ts +29 -0
- package/packages/native-plugins/mobile-signals/src/web.d.ts.map +1 -0
- package/packages/native-plugins/mobile-signals/src/web.js +269 -0
- package/packages/shared/src/app-hero-art.d.ts.map +1 -1
- package/packages/shared/src/app-hero-art.js +13 -0
- package/packages/shared/src/contracts/lifeops.d.ts +10 -0
- package/packages/shared/src/contracts/lifeops.d.ts.map +1 -1
- package/packages/shared/src/contracts/lifeops.js +5 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/actions/record-experience.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/actions/record-experience.js +46 -4
- package/packages/typescript/src/features/advanced-capabilities/experience/evaluators/experienceEvaluator.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/evaluators/experienceEvaluator.js +34 -124
- package/packages/typescript/src/features/advanced-capabilities/experience/service.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/service.js +56 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/types.d.ts +7 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/types.d.ts.map +1 -1
- package/packages/typescript/src/features/advanced-capabilities/experience/utils/experienceText.d.ts +7 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/utils/experienceText.d.ts.map +1 -0
- package/packages/typescript/src/features/advanced-capabilities/experience/utils/experienceText.js +123 -0
- package/apps/app-training/src/ui/FineTuningView.d.ts +0 -5
- package/apps/app-training/src/ui/FineTuningView.d.ts.map +0 -1
- package/apps/app-training/src/ui/FineTuningView.js +0 -388
- package/apps/app-training/src/ui/fine-tuning-panels.d.ts +0 -111
- package/apps/app-training/src/ui/fine-tuning-panels.d.ts.map +0 -1
- package/apps/app-training/src/ui/fine-tuning-panels.js +0 -130
- package/apps/app-training/src/ui/index.d.ts +0 -3
- package/apps/app-training/src/ui/index.d.ts.map +0 -1
- package/apps/app-training/src/ui/index.js +0 -2
- package/packages/app-core/src/api/trusted-local-request.d.ts +0 -4
- package/packages/app-core/src/api/trusted-local-request.d.ts.map +0 -1
- package/packages/app-core/src/api/trusted-local-request.js +0 -176
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { client, useApp } from "@elizaos/app-core";
|
|
3
|
+
import { AlarmClock, Apple, Bell, Check, ChevronDown, Clock, Loader2, MessageSquare, Plus, RefreshCw, Repeat, Trash2, } from "lucide-react";
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
5
|
+
import { useLifeOpsChatLauncher } from "./LifeOpsChatAdapter.js";
|
|
6
|
+
import { useLifeOpsSelection, } from "./LifeOpsSelectionContext.js";
|
|
7
|
+
const URGENCY_STYLES = {
|
|
8
|
+
overdue: {
|
|
9
|
+
label: "Overdue",
|
|
10
|
+
dot: "bg-rose-500",
|
|
11
|
+
pill: "bg-rose-500/15 text-rose-300",
|
|
12
|
+
accent: "bg-rose-500/70",
|
|
13
|
+
chip: "text-rose-300",
|
|
14
|
+
},
|
|
15
|
+
soon: {
|
|
16
|
+
label: "Within the hour",
|
|
17
|
+
dot: "bg-amber-400",
|
|
18
|
+
pill: "bg-amber-500/15 text-amber-300",
|
|
19
|
+
accent: "bg-amber-400/70",
|
|
20
|
+
chip: "text-amber-300",
|
|
21
|
+
},
|
|
22
|
+
today: {
|
|
23
|
+
label: "Today",
|
|
24
|
+
dot: "bg-blue-400",
|
|
25
|
+
pill: "bg-blue-500/15 text-blue-300",
|
|
26
|
+
accent: "bg-blue-400/70",
|
|
27
|
+
chip: "text-blue-300",
|
|
28
|
+
},
|
|
29
|
+
later: {
|
|
30
|
+
label: "Later this week",
|
|
31
|
+
dot: "bg-emerald-400",
|
|
32
|
+
pill: "bg-emerald-500/15 text-emerald-300",
|
|
33
|
+
accent: "bg-emerald-400/70",
|
|
34
|
+
chip: "text-emerald-300",
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const BUCKET_ORDER = ["overdue", "soon", "today", "later"];
|
|
38
|
+
// Mirror of NATIVE_APPLE_REMINDER_METADATA_KEY from
|
|
39
|
+
// `eliza/apps/app-lifeops/src/lifeops/apple-reminders.ts` — that module pulls
|
|
40
|
+
// in `node:child_process` so we cannot import it from a browser bundle.
|
|
41
|
+
// Keep this constant in sync with apple-reminders.ts.
|
|
42
|
+
const NATIVE_APPLE_REMINDER_METADATA_KEY = "nativeAppleReminder";
|
|
43
|
+
const WEEKDAY_LABELS = [
|
|
44
|
+
{ key: 1, short: "M", long: "Monday" },
|
|
45
|
+
{ key: 2, short: "T", long: "Tuesday" },
|
|
46
|
+
{ key: 3, short: "W", long: "Wednesday" },
|
|
47
|
+
{ key: 4, short: "T", long: "Thursday" },
|
|
48
|
+
{ key: 5, short: "F", long: "Friday" },
|
|
49
|
+
{ key: 6, short: "S", long: "Saturday" },
|
|
50
|
+
{ key: 0, short: "S", long: "Sunday" },
|
|
51
|
+
];
|
|
52
|
+
const SUPPORTED_CHANNEL_OPTIONS = [
|
|
53
|
+
{ value: "default", label: "Use default" },
|
|
54
|
+
{ value: "push", label: "Force push" },
|
|
55
|
+
{ value: "sms", label: "Force SMS" },
|
|
56
|
+
{ value: "email", label: "Force email" },
|
|
57
|
+
{ value: "telegram", label: "Force Telegram" },
|
|
58
|
+
{ value: "imessage", label: "Force iMessage" },
|
|
59
|
+
];
|
|
60
|
+
const SNOOZE_OPTIONS = [
|
|
61
|
+
{ key: "5m", label: "+5 min", request: { minutes: 5 } },
|
|
62
|
+
{ key: "15m", label: "+15 min", request: { preset: "15m" } },
|
|
63
|
+
{ key: "30m", label: "+30 min", request: { preset: "30m" } },
|
|
64
|
+
{ key: "1h", label: "+1 hour", request: { preset: "1h" } },
|
|
65
|
+
{ key: "1d", label: "+1 day", request: { minutes: 60 * 24 } },
|
|
66
|
+
];
|
|
67
|
+
const DEFAULT_SNOOZE = SNOOZE_OPTIONS[1] ?? {
|
|
68
|
+
key: "15m",
|
|
69
|
+
label: "+15 min",
|
|
70
|
+
request: { preset: "15m" },
|
|
71
|
+
};
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Pure helpers
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
function classifyReminder(iso) {
|
|
76
|
+
const parsed = Date.parse(iso);
|
|
77
|
+
if (!Number.isFinite(parsed))
|
|
78
|
+
return "later";
|
|
79
|
+
const diffMin = Math.round((parsed - Date.now()) / 60_000);
|
|
80
|
+
if (diffMin < 0)
|
|
81
|
+
return "overdue";
|
|
82
|
+
if (diffMin < 60)
|
|
83
|
+
return "soon";
|
|
84
|
+
if (diffMin < 60 * 24)
|
|
85
|
+
return "today";
|
|
86
|
+
return "later";
|
|
87
|
+
}
|
|
88
|
+
function formatRelative(iso) {
|
|
89
|
+
const parsed = Date.parse(iso);
|
|
90
|
+
if (!Number.isFinite(parsed))
|
|
91
|
+
return iso;
|
|
92
|
+
const diffMin = Math.round((parsed - Date.now()) / 60_000);
|
|
93
|
+
if (Math.abs(diffMin) < 1)
|
|
94
|
+
return "now";
|
|
95
|
+
if (diffMin > 0) {
|
|
96
|
+
if (diffMin < 60)
|
|
97
|
+
return `in ${diffMin}m`;
|
|
98
|
+
const hrs = Math.round(diffMin / 60);
|
|
99
|
+
if (hrs < 24)
|
|
100
|
+
return `in ${hrs}h`;
|
|
101
|
+
return `in ${Math.round(hrs / 24)}d`;
|
|
102
|
+
}
|
|
103
|
+
const ago = Math.abs(diffMin);
|
|
104
|
+
if (ago < 60)
|
|
105
|
+
return `${ago}m ago`;
|
|
106
|
+
const agoH = Math.round(ago / 60);
|
|
107
|
+
if (agoH < 24)
|
|
108
|
+
return `${agoH}h ago`;
|
|
109
|
+
return `${Math.round(agoH / 24)}d ago`;
|
|
110
|
+
}
|
|
111
|
+
function formatClock(iso) {
|
|
112
|
+
const date = new Date(iso);
|
|
113
|
+
if (!Number.isFinite(date.getTime()))
|
|
114
|
+
return iso;
|
|
115
|
+
return new Intl.DateTimeFormat(undefined, {
|
|
116
|
+
month: "short",
|
|
117
|
+
day: "numeric",
|
|
118
|
+
hour: "numeric",
|
|
119
|
+
minute: "2-digit",
|
|
120
|
+
}).format(date);
|
|
121
|
+
}
|
|
122
|
+
function formatTimeOfDay(iso) {
|
|
123
|
+
const date = new Date(iso);
|
|
124
|
+
if (!Number.isFinite(date.getTime())) {
|
|
125
|
+
return { primary: iso, suffix: "" };
|
|
126
|
+
}
|
|
127
|
+
const formatter = new Intl.DateTimeFormat(undefined, {
|
|
128
|
+
hour: "numeric",
|
|
129
|
+
minute: "2-digit",
|
|
130
|
+
hour12: true,
|
|
131
|
+
});
|
|
132
|
+
const formatted = formatter.format(date);
|
|
133
|
+
// Split off the trailing AM/PM if present so we can render it small.
|
|
134
|
+
const match = formatted.match(/^(.*?)(\s*[AaPp][Mm])$/);
|
|
135
|
+
if (match) {
|
|
136
|
+
return { primary: match[1].trim(), suffix: match[2].trim() };
|
|
137
|
+
}
|
|
138
|
+
return { primary: formatted, suffix: "" };
|
|
139
|
+
}
|
|
140
|
+
function formatNextFireDay(iso) {
|
|
141
|
+
const date = new Date(iso);
|
|
142
|
+
if (!Number.isFinite(date.getTime()))
|
|
143
|
+
return "";
|
|
144
|
+
const now = new Date();
|
|
145
|
+
const isSameDay = date.getFullYear() === now.getFullYear() &&
|
|
146
|
+
date.getMonth() === now.getMonth() &&
|
|
147
|
+
date.getDate() === now.getDate();
|
|
148
|
+
if (isSameDay)
|
|
149
|
+
return "Today";
|
|
150
|
+
const tomorrow = new Date(now);
|
|
151
|
+
tomorrow.setDate(now.getDate() + 1);
|
|
152
|
+
if (date.getFullYear() === tomorrow.getFullYear() &&
|
|
153
|
+
date.getMonth() === tomorrow.getMonth() &&
|
|
154
|
+
date.getDate() === tomorrow.getDate()) {
|
|
155
|
+
return "Tomorrow";
|
|
156
|
+
}
|
|
157
|
+
return new Intl.DateTimeFormat(undefined, {
|
|
158
|
+
weekday: "short",
|
|
159
|
+
month: "short",
|
|
160
|
+
day: "numeric",
|
|
161
|
+
}).format(date);
|
|
162
|
+
}
|
|
163
|
+
function channelLabel(channel) {
|
|
164
|
+
switch (channel) {
|
|
165
|
+
case "telegram":
|
|
166
|
+
return "Telegram";
|
|
167
|
+
case "discord":
|
|
168
|
+
return "Discord";
|
|
169
|
+
case "imessage":
|
|
170
|
+
return "iMessage";
|
|
171
|
+
case "signal":
|
|
172
|
+
return "Signal";
|
|
173
|
+
case "push":
|
|
174
|
+
return "Push";
|
|
175
|
+
case "email":
|
|
176
|
+
return "Email";
|
|
177
|
+
case "sms":
|
|
178
|
+
return "SMS";
|
|
179
|
+
case "in_app":
|
|
180
|
+
return "In-app";
|
|
181
|
+
case "voice":
|
|
182
|
+
return "Voice";
|
|
183
|
+
case "whatsapp":
|
|
184
|
+
return "WhatsApp";
|
|
185
|
+
default:
|
|
186
|
+
return channel;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function isRecord(value) {
|
|
190
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
191
|
+
}
|
|
192
|
+
function readNativeAppleMetadata(metadata) {
|
|
193
|
+
if (!isRecord(metadata))
|
|
194
|
+
return null;
|
|
195
|
+
const raw = metadata[NATIVE_APPLE_REMINDER_METADATA_KEY];
|
|
196
|
+
if (!isRecord(raw))
|
|
197
|
+
return null;
|
|
198
|
+
const kind = raw.kind === "alarm" || raw.kind === "reminder" ? raw.kind : null;
|
|
199
|
+
if (!kind)
|
|
200
|
+
return null;
|
|
201
|
+
const reminderId = typeof raw.reminderId === "string" && raw.reminderId.trim().length > 0
|
|
202
|
+
? raw.reminderId.trim()
|
|
203
|
+
: null;
|
|
204
|
+
return { kind, reminderId };
|
|
205
|
+
}
|
|
206
|
+
function describeRecurrence(cadence) {
|
|
207
|
+
if (!cadence)
|
|
208
|
+
return null;
|
|
209
|
+
switch (cadence.kind) {
|
|
210
|
+
case "once":
|
|
211
|
+
return null;
|
|
212
|
+
case "daily":
|
|
213
|
+
return "Daily";
|
|
214
|
+
case "interval": {
|
|
215
|
+
const minutes = cadence.everyMinutes;
|
|
216
|
+
if (minutes >= 60 && minutes % 60 === 0) {
|
|
217
|
+
const hours = minutes / 60;
|
|
218
|
+
return hours === 1 ? "Every hour" : `Every ${hours}h`;
|
|
219
|
+
}
|
|
220
|
+
return `Every ${minutes}m`;
|
|
221
|
+
}
|
|
222
|
+
case "times_per_day": {
|
|
223
|
+
const slots = cadence.slots?.length ?? 0;
|
|
224
|
+
return slots > 0 ? `${slots}x/day` : "Daily";
|
|
225
|
+
}
|
|
226
|
+
case "weekly": {
|
|
227
|
+
const weekdays = Array.isArray(cadence.weekdays) ? cadence.weekdays : [];
|
|
228
|
+
if (weekdays.length === 0)
|
|
229
|
+
return "Weekly";
|
|
230
|
+
if (weekdays.length === 7)
|
|
231
|
+
return "Daily";
|
|
232
|
+
const labels = WEEKDAY_LABELS.filter((day) => weekdays.includes(day.key))
|
|
233
|
+
.sort((a, b) => {
|
|
234
|
+
// Sort Mon..Sun (0=Sun -> last)
|
|
235
|
+
const order = (k) => (k === 0 ? 7 : k);
|
|
236
|
+
return order(a.key) - order(b.key);
|
|
237
|
+
})
|
|
238
|
+
.map((day) => day.long.slice(0, 3));
|
|
239
|
+
return `Weekly ${labels.join("/")}`;
|
|
240
|
+
}
|
|
241
|
+
default:
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function pickAlarmCadence(hour, minute, weekdays, timezone) {
|
|
246
|
+
const minuteOfDay = hour * 60 + minute;
|
|
247
|
+
if (weekdays.size === 0) {
|
|
248
|
+
// Single-fire: schedule next occurrence of HH:MM (today if still in the
|
|
249
|
+
// future, otherwise tomorrow).
|
|
250
|
+
const now = new Date();
|
|
251
|
+
const candidate = new Date(now);
|
|
252
|
+
candidate.setHours(hour, minute, 0, 0);
|
|
253
|
+
if (candidate.getTime() <= now.getTime()) {
|
|
254
|
+
candidate.setDate(candidate.getDate() + 1);
|
|
255
|
+
}
|
|
256
|
+
return { kind: "once", dueAt: candidate.toISOString() };
|
|
257
|
+
}
|
|
258
|
+
if (weekdays.size === 7) {
|
|
259
|
+
return {
|
|
260
|
+
kind: "times_per_day",
|
|
261
|
+
slots: [
|
|
262
|
+
{
|
|
263
|
+
key: "alarm",
|
|
264
|
+
label: "Alarm",
|
|
265
|
+
minuteOfDay,
|
|
266
|
+
durationMinutes: 1,
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
kind: "weekly",
|
|
273
|
+
weekdays: Array.from(weekdays).sort((a, b) => a - b),
|
|
274
|
+
windows: [],
|
|
275
|
+
visibilityLeadMinutes: 0,
|
|
276
|
+
visibilityLagMinutes: 0,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function defaultTimezone() {
|
|
280
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
281
|
+
}
|
|
282
|
+
function SnoozeSplitButton({ occurrenceId, busyAction, optimisticState, onSnooze, onCustomSnooze, }) {
|
|
283
|
+
const [open, setOpen] = useState(false);
|
|
284
|
+
const containerRef = useRef(null);
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
if (!open)
|
|
287
|
+
return;
|
|
288
|
+
const onDoc = (event) => {
|
|
289
|
+
if (!containerRef.current)
|
|
290
|
+
return;
|
|
291
|
+
if (!containerRef.current.contains(event.target)) {
|
|
292
|
+
setOpen(false);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
document.addEventListener("mousedown", onDoc);
|
|
296
|
+
return () => document.removeEventListener("mousedown", onDoc);
|
|
297
|
+
}, [open]);
|
|
298
|
+
const disabled = !occurrenceId || optimisticState !== "idle" || busyAction !== null;
|
|
299
|
+
return (_jsxs("div", { ref: containerRef, className: "relative inline-flex items-stretch overflow-hidden rounded-lg border border-border/15 bg-bg-muted/30 text-[11px] font-semibold text-muted", children: [_jsxs("button", { type: "button", disabled: disabled, onClick: () => onSnooze(DEFAULT_SNOOZE), className: "inline-flex items-center gap-1 px-2 py-1 transition-colors hover:bg-bg-muted/60 hover:text-txt disabled:cursor-not-allowed disabled:opacity-40", title: occurrenceId
|
|
300
|
+
? `Snooze ${DEFAULT_SNOOZE.label}`
|
|
301
|
+
: "Snooze unavailable for this reminder", "aria-label": `Snooze ${DEFAULT_SNOOZE.label}`, children: [busyAction === "snooze" ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin" })) : (_jsx(Clock, { className: "h-3 w-3", "aria-hidden": true })), DEFAULT_SNOOZE.label] }), _jsx("button", { type: "button", disabled: disabled, onClick: () => setOpen((prev) => !prev), className: "inline-flex items-center border-l border-border/15 px-1.5 py-1 transition-colors hover:bg-bg-muted/60 hover:text-txt disabled:cursor-not-allowed disabled:opacity-40", "aria-label": "Snooze options", "aria-expanded": open, children: _jsx(ChevronDown, { className: "h-3 w-3", "aria-hidden": true }) }), open ? (_jsxs("div", { role: "menu", className: "absolute right-0 top-full z-20 mt-1 w-40 overflow-hidden rounded-lg border border-border/20 bg-card shadow-lg", children: [SNOOZE_OPTIONS.map((option) => (_jsx("button", { type: "button", role: "menuitem", onClick: () => {
|
|
302
|
+
setOpen(false);
|
|
303
|
+
onSnooze(option);
|
|
304
|
+
}, className: "block w-full px-3 py-1.5 text-left text-[11px] font-medium text-txt transition-colors hover:bg-bg-muted/40", children: option.label }, option.key))), _jsx("button", { type: "button", role: "menuitem", onClick: () => {
|
|
305
|
+
setOpen(false);
|
|
306
|
+
onCustomSnooze();
|
|
307
|
+
}, className: "block w-full border-t border-border/12 px-3 py-1.5 text-left text-[11px] font-medium text-txt transition-colors hover:bg-bg-muted/40", children: "Custom\u2026" })] })) : null] }));
|
|
308
|
+
}
|
|
309
|
+
function CompleteButton({ occurrenceId, busyAction, optimisticState, onComplete, }) {
|
|
310
|
+
const disabled = !occurrenceId || optimisticState !== "idle" || busyAction !== null;
|
|
311
|
+
return (_jsx("button", { type: "button", disabled: disabled, onClick: onComplete, className: "inline-flex h-7 w-7 items-center justify-center rounded-lg border border-border/15 bg-bg-muted/30 text-emerald-300 transition-colors hover:bg-emerald-500/15 hover:text-emerald-200 disabled:cursor-not-allowed disabled:opacity-40", title: occurrenceId
|
|
312
|
+
? "Mark complete"
|
|
313
|
+
: "Complete unavailable for this reminder", "aria-label": "Mark complete", children: busyAction === "complete" ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(Check, { className: "h-3.5 w-3.5", "aria-hidden": true })) }));
|
|
314
|
+
}
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
// Channel override popover
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
function ChannelOverridePopover({ channel }) {
|
|
319
|
+
const [open, setOpen] = useState(false);
|
|
320
|
+
const ref = useRef(null);
|
|
321
|
+
useEffect(() => {
|
|
322
|
+
if (!open)
|
|
323
|
+
return;
|
|
324
|
+
const onDoc = (event) => {
|
|
325
|
+
if (!ref.current)
|
|
326
|
+
return;
|
|
327
|
+
if (!ref.current.contains(event.target)) {
|
|
328
|
+
setOpen(false);
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
document.addEventListener("mousedown", onDoc);
|
|
332
|
+
return () => document.removeEventListener("mousedown", onDoc);
|
|
333
|
+
}, [open]);
|
|
334
|
+
return (_jsxs("span", { ref: ref, className: "relative inline-flex", children: [_jsxs("button", { type: "button", onClick: (e) => {
|
|
335
|
+
e.stopPropagation();
|
|
336
|
+
setOpen((prev) => !prev);
|
|
337
|
+
}, className: "inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px] font-medium text-muted/80 hover:bg-bg-muted/50 hover:text-txt", "aria-label": `Change delivery channel (currently ${channelLabel(channel)})`, "aria-expanded": open, children: ["via ", channelLabel(channel)] }), open ? (_jsxs("div", { role: "menu", className: "absolute left-0 top-full z-20 mt-1 w-44 overflow-hidden rounded-lg border border-border/20 bg-card shadow-lg", onClick: (e) => e.stopPropagation(), children: [SUPPORTED_CHANNEL_OPTIONS.map((option) => (_jsx("div", { role: "menuitem", className: "px-3 py-1.5 text-[11px] text-muted opacity-60", title: "Channel override API not yet wired \u2014 Coming soon", children: option.label }, option.value))), _jsx("div", { className: "border-t border-border/12 px-3 py-1.5 text-[10px] text-muted/70", children: "Coming soon" })] })) : null] }));
|
|
338
|
+
}
|
|
339
|
+
function ReminderRow({ reminder, urgency, isSelected, apple, recurrence, busyAction, optimisticState, onSelect, onChat, onSnooze, onComplete, onCustomSnooze, }) {
|
|
340
|
+
const style = URGENCY_STYLES[urgency];
|
|
341
|
+
const occurrenceId = reminder.occurrenceId;
|
|
342
|
+
const fading = optimisticState !== "idle";
|
|
343
|
+
return (_jsxs("div", { className: [
|
|
344
|
+
"group flex items-stretch gap-2 border-b border-border/8 pr-3 last:border-b-0",
|
|
345
|
+
isSelected ? "bg-accent/8" : "hover:bg-bg-muted/25",
|
|
346
|
+
fading ? "opacity-50" : "",
|
|
347
|
+
].join(" "), children: [_jsxs("button", { type: "button", "aria-pressed": isSelected, className: "flex min-w-0 flex-1 items-stretch gap-3 text-left", onClick: onSelect, children: [_jsx("span", { "aria-hidden": true, className: `w-1 shrink-0 ${style.accent} ${isSelected ? "" : "opacity-70 group-hover:opacity-100"}` }), _jsxs("span", { className: "flex min-w-0 flex-1 items-start gap-3 py-2.5", children: [_jsx("span", { className: "mt-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-bg-muted/30 text-muted", children: _jsx(Bell, { className: "h-3.5 w-3.5", "aria-hidden": true }) }), _jsxs("span", { className: "min-w-0 flex-1 space-y-0.5", children: [_jsxs("span", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx("span", { className: "truncate text-sm font-medium text-txt", children: reminder.title }), recurrence ? (_jsxs("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-bg-muted/40 px-1.5 py-0 text-[10px] font-medium text-muted", title: `Repeats: ${recurrence}`, children: [_jsx(Repeat, { className: "h-2.5 w-2.5", "aria-hidden": true }), recurrence] })) : null, _jsx(SourceBadge, { apple: apple }), optimisticState === "snoozed" ? (_jsx("span", { className: "rounded-full bg-blue-500/15 px-1.5 py-0 text-[10px] font-medium text-blue-300", children: "snoozed" })) : null, optimisticState === "completed" ? (_jsx("span", { className: "rounded-full bg-emerald-500/15 px-1.5 py-0 text-[10px] font-medium text-emerald-300", children: "completed" })) : null] }), _jsxs("span", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-muted", children: [_jsx("span", { children: formatClock(reminder.scheduledFor) }), reminder.stepLabel ? (_jsxs("span", { className: "text-muted/70", children: ["\u00B7 ", reminder.stepLabel] })) : null, _jsx("span", { className: "text-muted/70", children: "\u00B7" }), _jsx(ChannelOverridePopover, { channel: reminder.channel })] })] }), _jsx("span", { className: `mt-1 shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold tabular-nums ${style.pill}`, children: formatRelative(reminder.scheduledFor) })] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5 py-2.5", children: [_jsx(SnoozeSplitButton, { occurrenceId: occurrenceId, busyAction: busyAction, optimisticState: optimisticState, onSnooze: onSnooze, onCustomSnooze: onCustomSnooze }), _jsx(CompleteButton, { occurrenceId: occurrenceId, busyAction: busyAction, optimisticState: optimisticState, onComplete: onComplete }), _jsxs("button", { type: "button", onClick: onChat, className: "inline-flex h-7 items-center gap-1.5 rounded-lg px-2.5 text-[11px] font-semibold text-muted transition-colors hover:bg-bg-muted/40 hover:text-txt", "aria-label": `Chat about ${reminder.title}`, children: [_jsx(MessageSquare, { className: "h-3.5 w-3.5", "aria-hidden": true }), "Chat"] })] })] }));
|
|
348
|
+
}
|
|
349
|
+
function SourceBadge({ apple, }) {
|
|
350
|
+
if (apple) {
|
|
351
|
+
return (_jsxs("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-rose-500/15 px-1.5 py-0 text-[10px] font-medium text-rose-200", title: "Mirrored to your Apple Reminders app via the native macOS integration.", children: [_jsx(Apple, { className: "h-2.5 w-2.5", "aria-hidden": true }), "Apple Reminders"] }));
|
|
352
|
+
}
|
|
353
|
+
return (_jsx("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-bg-muted/40 px-1.5 py-0 text-[10px] font-medium text-muted", title: "Delivered in-app by Eliza only \u2014 not mirrored to a native reminder service.", children: "In-app" }));
|
|
354
|
+
}
|
|
355
|
+
function BucketHeader({ urgency, count, }) {
|
|
356
|
+
const style = URGENCY_STYLES[urgency];
|
|
357
|
+
return (_jsxs("div", { className: "flex items-center gap-2 px-1 py-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted", children: [_jsx("span", { className: `h-1.5 w-1.5 rounded-full ${style.dot}`, "aria-hidden": true }), _jsx("span", { className: style.chip, children: style.label }), _jsxs("span", { className: "text-muted/60", children: ["\u00B7 ", count] })] }));
|
|
358
|
+
}
|
|
359
|
+
function buildAlarmEntries(definitions, reminders) {
|
|
360
|
+
const remindersByDefId = new Map();
|
|
361
|
+
for (const reminder of reminders) {
|
|
362
|
+
if (reminder.definitionId && !remindersByDefId.has(reminder.definitionId)) {
|
|
363
|
+
remindersByDefId.set(reminder.definitionId, reminder);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const entries = [];
|
|
367
|
+
for (const record of definitions) {
|
|
368
|
+
const apple = readNativeAppleMetadata(record.definition.metadata);
|
|
369
|
+
if (!apple || apple.kind !== "alarm")
|
|
370
|
+
continue;
|
|
371
|
+
if (record.definition.status === "archived")
|
|
372
|
+
continue;
|
|
373
|
+
const reminder = remindersByDefId.get(record.definition.id) ?? null;
|
|
374
|
+
const recurrence = describeRecurrence(record.definition.cadence) ?? "Once";
|
|
375
|
+
const nextFireIso = computeNextFireIso(record.definition, reminder);
|
|
376
|
+
entries.push({
|
|
377
|
+
definition: record.definition,
|
|
378
|
+
reminder,
|
|
379
|
+
recurrence,
|
|
380
|
+
nextFireIso,
|
|
381
|
+
apple,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
entries.sort((a, b) => {
|
|
385
|
+
if (a.nextFireIso && b.nextFireIso) {
|
|
386
|
+
return a.nextFireIso.localeCompare(b.nextFireIso);
|
|
387
|
+
}
|
|
388
|
+
if (a.nextFireIso)
|
|
389
|
+
return -1;
|
|
390
|
+
if (b.nextFireIso)
|
|
391
|
+
return 1;
|
|
392
|
+
return a.definition.title.localeCompare(b.definition.title);
|
|
393
|
+
});
|
|
394
|
+
return entries;
|
|
395
|
+
}
|
|
396
|
+
function computeNextFireIso(definition, reminder) {
|
|
397
|
+
if (reminder?.scheduledFor)
|
|
398
|
+
return reminder.scheduledFor;
|
|
399
|
+
const cadence = definition.cadence;
|
|
400
|
+
const now = new Date();
|
|
401
|
+
if (cadence.kind === "once")
|
|
402
|
+
return cadence.dueAt;
|
|
403
|
+
if (cadence.kind === "times_per_day") {
|
|
404
|
+
const slot = cadence.slots?.[0];
|
|
405
|
+
if (!slot)
|
|
406
|
+
return null;
|
|
407
|
+
const candidate = new Date(now);
|
|
408
|
+
candidate.setHours(0, 0, 0, 0);
|
|
409
|
+
candidate.setMinutes(slot.minuteOfDay);
|
|
410
|
+
if (candidate.getTime() <= now.getTime()) {
|
|
411
|
+
candidate.setDate(candidate.getDate() + 1);
|
|
412
|
+
}
|
|
413
|
+
return candidate.toISOString();
|
|
414
|
+
}
|
|
415
|
+
if (cadence.kind === "weekly") {
|
|
416
|
+
const weekdays = cadence.weekdays ?? [];
|
|
417
|
+
if (weekdays.length === 0)
|
|
418
|
+
return null;
|
|
419
|
+
// We don't know the time-of-day in the weekly cadence; fall back to now+1d.
|
|
420
|
+
const candidate = new Date(now);
|
|
421
|
+
for (let offset = 0; offset < 8; offset += 1) {
|
|
422
|
+
const probe = new Date(candidate);
|
|
423
|
+
probe.setDate(candidate.getDate() + offset);
|
|
424
|
+
if (weekdays.includes(probe.getDay())) {
|
|
425
|
+
return probe.toISOString();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
function AddAlarmForm({ saving, onSave, onCancel }) {
|
|
432
|
+
const [time, setTime] = useState("07:00");
|
|
433
|
+
const [label, setLabel] = useState("");
|
|
434
|
+
const [weekdays, setWeekdays] = useState(new Set());
|
|
435
|
+
const toggleWeekday = (key) => {
|
|
436
|
+
setWeekdays((prev) => {
|
|
437
|
+
const next = new Set(prev);
|
|
438
|
+
if (next.has(key)) {
|
|
439
|
+
next.delete(key);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
next.add(key);
|
|
443
|
+
}
|
|
444
|
+
return next;
|
|
445
|
+
});
|
|
446
|
+
};
|
|
447
|
+
const handleSubmit = (event) => {
|
|
448
|
+
event.preventDefault();
|
|
449
|
+
const [hStr, mStr] = time.split(":");
|
|
450
|
+
const hour = Number.parseInt(hStr ?? "", 10);
|
|
451
|
+
const minute = Number.parseInt(mStr ?? "", 10);
|
|
452
|
+
if (!Number.isFinite(hour) || hour < 0 || hour > 23)
|
|
453
|
+
return;
|
|
454
|
+
if (!Number.isFinite(minute) || minute < 0 || minute > 59)
|
|
455
|
+
return;
|
|
456
|
+
onSave({ label: label.trim(), hour, minute, weekdays });
|
|
457
|
+
};
|
|
458
|
+
return (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-3 rounded-2xl border border-border/15 bg-card/30 p-4", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("label", { className: "flex flex-col gap-1 text-[11px] font-medium text-muted", children: ["Time", _jsx("input", { type: "time", value: time, onChange: (e) => setTime(e.target.value), className: "rounded-lg border border-border/20 bg-bg-muted/30 px-3 py-1.5 text-base font-semibold text-txt tabular-nums focus:border-accent focus:outline-none", required: true })] }), _jsxs("label", { className: "flex min-w-[12rem] flex-1 flex-col gap-1 text-[11px] font-medium text-muted", children: ["Label (optional)", _jsx("input", { type: "text", value: label, onChange: (e) => setLabel(e.target.value), placeholder: "Morning workout", className: "rounded-lg border border-border/20 bg-bg-muted/30 px-3 py-1.5 text-sm text-txt focus:border-accent focus:outline-none", maxLength: 120 })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("span", { className: "text-[11px] font-medium text-muted", children: "Repeat" }), _jsx("div", { className: "flex flex-wrap gap-1", children: WEEKDAY_LABELS.map((day) => {
|
|
459
|
+
const active = weekdays.has(day.key);
|
|
460
|
+
return (_jsx("button", { type: "button", onClick: () => toggleWeekday(day.key), "aria-pressed": active, title: day.long, className: [
|
|
461
|
+
"h-8 w-8 rounded-full border text-[11px] font-semibold transition-colors",
|
|
462
|
+
active
|
|
463
|
+
? "border-accent bg-accent/20 text-accent"
|
|
464
|
+
: "border-border/20 bg-bg-muted/20 text-muted hover:bg-bg-muted/40",
|
|
465
|
+
].join(" "), children: day.short }, day.key));
|
|
466
|
+
}) }), _jsx("p", { className: "pt-0.5 text-[10px] text-muted/70", children: weekdays.size === 0
|
|
467
|
+
? "Single fire (next occurrence)."
|
|
468
|
+
: weekdays.size === 7
|
|
469
|
+
? "Repeats every day."
|
|
470
|
+
: `Repeats on ${weekdays.size} day${weekdays.size === 1 ? "" : "s"}.` })] }), _jsxs("div", { className: "flex items-center justify-end gap-2 pt-1", children: [_jsx("button", { type: "button", onClick: onCancel, className: "rounded-lg px-3 py-1.5 text-[11px] font-semibold text-muted hover:bg-bg-muted/40 hover:text-txt", children: "Cancel" }), _jsxs("button", { type: "submit", disabled: saving, className: "inline-flex items-center gap-1.5 rounded-lg bg-accent px-3 py-1.5 text-[11px] font-semibold text-bg shadow-sm transition-colors hover:bg-accent/90 disabled:opacity-50", children: [saving ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : null, "Save alarm"] })] })] }));
|
|
471
|
+
}
|
|
472
|
+
function AlarmRow({ entry, busyAction, optimisticState, onSnooze, onComplete, onCustomSnooze, onDelete, }) {
|
|
473
|
+
const occurrenceId = entry.reminder?.occurrenceId ?? null;
|
|
474
|
+
const time = entry.nextFireIso ? formatTimeOfDay(entry.nextFireIso) : null;
|
|
475
|
+
const day = entry.nextFireIso ? formatNextFireDay(entry.nextFireIso) : "";
|
|
476
|
+
const fading = optimisticState !== "idle";
|
|
477
|
+
return (_jsxs("div", { className: [
|
|
478
|
+
"flex flex-wrap items-center gap-4 rounded-2xl border border-border/15 bg-card/30 px-4 py-3",
|
|
479
|
+
fading ? "opacity-50" : "",
|
|
480
|
+
].join(" "), children: [_jsx("div", { className: "flex min-w-[10rem] items-baseline gap-1", children: time ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-mono text-4xl font-light tabular-nums text-txt", children: time.primary }), time.suffix ? (_jsx("span", { className: "text-xs font-medium uppercase text-muted", children: time.suffix })) : null] })) : (_jsx("span", { className: "text-2xl font-light text-muted", children: "--:--" })) }), _jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx("span", { className: "truncate text-sm font-medium text-txt", children: entry.definition.title }), _jsxs("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-bg-muted/40 px-1.5 py-0 text-[10px] font-medium text-muted", title: `Repeats: ${entry.recurrence}`, children: [_jsx(Repeat, { className: "h-2.5 w-2.5", "aria-hidden": true }), entry.recurrence] }), _jsx(SourceBadge, { apple: entry.apple }), optimisticState === "deleted" ? (_jsx("span", { className: "rounded-full bg-rose-500/15 px-1.5 py-0 text-[10px] font-medium text-rose-300", children: "deleted" })) : null] }), _jsxs("div", { className: "text-[11px] text-muted", children: [day ? `${day} · ` : "", entry.nextFireIso ? formatRelative(entry.nextFireIso) : "No upcoming fire"] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsx(SnoozeSplitButton, { occurrenceId: occurrenceId, busyAction: busyAction === "delete" ? null : busyAction, optimisticState: optimisticState === "deleted" ? "snoozed" : optimisticState, onSnooze: onSnooze, onCustomSnooze: onCustomSnooze }), _jsx(CompleteButton, { occurrenceId: occurrenceId, busyAction: busyAction === "delete" ? null : busyAction, optimisticState: optimisticState === "deleted" ? "completed" : optimisticState, onComplete: onComplete }), _jsx("button", { type: "button", onClick: onDelete, disabled: busyAction !== null || optimisticState === "deleted", className: "inline-flex h-7 w-7 items-center justify-center rounded-lg border border-border/15 bg-bg-muted/30 text-rose-300 transition-colors hover:bg-rose-500/15 hover:text-rose-200 disabled:cursor-not-allowed disabled:opacity-40", "aria-label": "Delete alarm", title: "Delete alarm", children: busyAction === "delete" ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(Trash2, { className: "h-3.5 w-3.5", "aria-hidden": true })) })] })] }));
|
|
481
|
+
}
|
|
482
|
+
// ---------------------------------------------------------------------------
|
|
483
|
+
// Top-level section
|
|
484
|
+
// ---------------------------------------------------------------------------
|
|
485
|
+
export function LifeOpsRemindersSection() {
|
|
486
|
+
const { t } = useApp();
|
|
487
|
+
const { selection, select } = useLifeOpsSelection();
|
|
488
|
+
const { chatAboutReminder } = useLifeOpsChatLauncher();
|
|
489
|
+
const [tab, setTab] = useState("reminders");
|
|
490
|
+
const [reminders, setReminders] = useState([]);
|
|
491
|
+
const [definitions, setDefinitions] = useState([]);
|
|
492
|
+
const [loading, setLoading] = useState(false);
|
|
493
|
+
const [error, setError] = useState(null);
|
|
494
|
+
const [showAddAlarm, setShowAddAlarm] = useState(false);
|
|
495
|
+
const [savingAlarm, setSavingAlarm] = useState(false);
|
|
496
|
+
const [rowState, setRowState] = useState({});
|
|
497
|
+
const setRowBusy = useCallback((key, busy) => {
|
|
498
|
+
setRowState((prev) => ({
|
|
499
|
+
...prev,
|
|
500
|
+
[key]: { ...(prev[key] ?? { optimistic: "idle" }), busy },
|
|
501
|
+
}));
|
|
502
|
+
}, []);
|
|
503
|
+
const setRowOptimistic = useCallback((key, optimistic) => {
|
|
504
|
+
setRowState((prev) => ({
|
|
505
|
+
...prev,
|
|
506
|
+
[key]: { ...(prev[key] ?? { busy: null }), optimistic },
|
|
507
|
+
}));
|
|
508
|
+
}, []);
|
|
509
|
+
const load = useCallback(async () => {
|
|
510
|
+
setLoading(true);
|
|
511
|
+
setError(null);
|
|
512
|
+
try {
|
|
513
|
+
const [overview, defs] = await Promise.all([
|
|
514
|
+
client.getLifeOpsOverview(),
|
|
515
|
+
client.listLifeOpsDefinitions(),
|
|
516
|
+
]);
|
|
517
|
+
setReminders(overview.reminders);
|
|
518
|
+
setDefinitions(defs.definitions);
|
|
519
|
+
setRowState({});
|
|
520
|
+
}
|
|
521
|
+
catch (cause) {
|
|
522
|
+
setError(cause instanceof Error
|
|
523
|
+
? cause.message
|
|
524
|
+
: t("lifeopsreminders.loadFailed", {
|
|
525
|
+
defaultValue: "Failed to load reminders.",
|
|
526
|
+
}));
|
|
527
|
+
}
|
|
528
|
+
finally {
|
|
529
|
+
setLoading(false);
|
|
530
|
+
}
|
|
531
|
+
}, [t]);
|
|
532
|
+
useEffect(() => {
|
|
533
|
+
void load();
|
|
534
|
+
}, [load]);
|
|
535
|
+
const definitionById = useMemo(() => {
|
|
536
|
+
const map = new Map();
|
|
537
|
+
for (const record of definitions) {
|
|
538
|
+
map.set(record.definition.id, record);
|
|
539
|
+
}
|
|
540
|
+
return map;
|
|
541
|
+
}, [definitions]);
|
|
542
|
+
const buckets = useMemo(() => {
|
|
543
|
+
const map = {
|
|
544
|
+
overdue: [],
|
|
545
|
+
soon: [],
|
|
546
|
+
today: [],
|
|
547
|
+
later: [],
|
|
548
|
+
};
|
|
549
|
+
for (const reminder of reminders) {
|
|
550
|
+
// Hide reminders whose backing definition is flagged as alarm — they
|
|
551
|
+
// live in the Alarms tab.
|
|
552
|
+
if (reminder.definitionId) {
|
|
553
|
+
const record = definitionById.get(reminder.definitionId);
|
|
554
|
+
const apple = readNativeAppleMetadata(record?.definition.metadata);
|
|
555
|
+
if (apple?.kind === "alarm")
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
map[classifyReminder(reminder.scheduledFor)].push(reminder);
|
|
559
|
+
}
|
|
560
|
+
for (const key of BUCKET_ORDER) {
|
|
561
|
+
map[key].sort((a, b) => a.scheduledFor.localeCompare(b.scheduledFor));
|
|
562
|
+
}
|
|
563
|
+
return map;
|
|
564
|
+
}, [reminders, definitionById]);
|
|
565
|
+
const reminderCount = useMemo(() => buckets.overdue.length +
|
|
566
|
+
buckets.soon.length +
|
|
567
|
+
buckets.today.length +
|
|
568
|
+
buckets.later.length, [buckets]);
|
|
569
|
+
const alarmEntries = useMemo(() => buildAlarmEntries(definitions, reminders), [definitions, reminders]);
|
|
570
|
+
const handleSnooze = useCallback(async (rowKey, occurrenceId, option) => {
|
|
571
|
+
if (!occurrenceId)
|
|
572
|
+
return;
|
|
573
|
+
setRowBusy(rowKey, "snooze");
|
|
574
|
+
try {
|
|
575
|
+
await client.snoozeLifeOpsOccurrence(occurrenceId, option.request);
|
|
576
|
+
setRowOptimistic(rowKey, "snoozed");
|
|
577
|
+
// Refetch shortly so the optimistic state can be reconciled.
|
|
578
|
+
setTimeout(() => {
|
|
579
|
+
void load();
|
|
580
|
+
}, 400);
|
|
581
|
+
}
|
|
582
|
+
catch (cause) {
|
|
583
|
+
setError(cause instanceof Error ? cause.message : "Snooze failed.");
|
|
584
|
+
}
|
|
585
|
+
finally {
|
|
586
|
+
setRowBusy(rowKey, null);
|
|
587
|
+
}
|
|
588
|
+
}, [load, setRowBusy, setRowOptimistic]);
|
|
589
|
+
const handleComplete = useCallback(async (rowKey, occurrenceId) => {
|
|
590
|
+
if (!occurrenceId)
|
|
591
|
+
return;
|
|
592
|
+
setRowBusy(rowKey, "complete");
|
|
593
|
+
try {
|
|
594
|
+
await client.completeLifeOpsOccurrence(occurrenceId, {});
|
|
595
|
+
setRowOptimistic(rowKey, "completed");
|
|
596
|
+
setTimeout(() => {
|
|
597
|
+
void load();
|
|
598
|
+
}, 400);
|
|
599
|
+
}
|
|
600
|
+
catch (cause) {
|
|
601
|
+
setError(cause instanceof Error ? cause.message : "Complete failed.");
|
|
602
|
+
}
|
|
603
|
+
finally {
|
|
604
|
+
setRowBusy(rowKey, null);
|
|
605
|
+
}
|
|
606
|
+
}, [load, setRowBusy, setRowOptimistic]);
|
|
607
|
+
const handleCustomSnooze = useCallback(async (rowKey, occurrenceId) => {
|
|
608
|
+
if (!occurrenceId)
|
|
609
|
+
return;
|
|
610
|
+
const raw = window.prompt("Snooze for how many minutes?", "45");
|
|
611
|
+
if (!raw)
|
|
612
|
+
return;
|
|
613
|
+
const minutes = Number.parseInt(raw, 10);
|
|
614
|
+
if (!Number.isFinite(minutes) || minutes <= 0) {
|
|
615
|
+
setError("Snooze duration must be a positive number of minutes.");
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
await handleSnooze(rowKey, occurrenceId, {
|
|
619
|
+
key: `custom-${minutes}`,
|
|
620
|
+
label: `+${minutes}m`,
|
|
621
|
+
request: { minutes },
|
|
622
|
+
});
|
|
623
|
+
}, [handleSnooze]);
|
|
624
|
+
const handleDeleteAlarm = useCallback(async (definitionId) => {
|
|
625
|
+
const rowKey = `alarm:${definitionId}`;
|
|
626
|
+
setRowBusy(rowKey, "delete");
|
|
627
|
+
try {
|
|
628
|
+
await client.updateLifeOpsDefinition(definitionId, {
|
|
629
|
+
status: "archived",
|
|
630
|
+
});
|
|
631
|
+
setRowOptimistic(rowKey, "deleted");
|
|
632
|
+
setTimeout(() => {
|
|
633
|
+
void load();
|
|
634
|
+
}, 400);
|
|
635
|
+
}
|
|
636
|
+
catch (cause) {
|
|
637
|
+
setError(cause instanceof Error ? cause.message : "Delete failed.");
|
|
638
|
+
}
|
|
639
|
+
finally {
|
|
640
|
+
setRowBusy(rowKey, null);
|
|
641
|
+
}
|
|
642
|
+
}, [load, setRowBusy, setRowOptimistic]);
|
|
643
|
+
const handleCreateAlarm = useCallback(async (input) => {
|
|
644
|
+
setSavingAlarm(true);
|
|
645
|
+
setError(null);
|
|
646
|
+
try {
|
|
647
|
+
const timezone = defaultTimezone();
|
|
648
|
+
const cadence = pickAlarmCadence(input.hour, input.minute, input.weekdays, timezone);
|
|
649
|
+
const title = input.label.length > 0
|
|
650
|
+
? input.label
|
|
651
|
+
: `Alarm ${String(input.hour).padStart(2, "0")}:${String(input.minute).padStart(2, "0")}`;
|
|
652
|
+
const request = {
|
|
653
|
+
kind: "task",
|
|
654
|
+
title,
|
|
655
|
+
description: "Eliza alarm.",
|
|
656
|
+
originalIntent: title,
|
|
657
|
+
timezone,
|
|
658
|
+
priority: 1,
|
|
659
|
+
cadence,
|
|
660
|
+
source: "lifeops_ui_alarm",
|
|
661
|
+
metadata: {
|
|
662
|
+
[NATIVE_APPLE_REMINDER_METADATA_KEY]: {
|
|
663
|
+
kind: "alarm",
|
|
664
|
+
provider: "apple_reminders",
|
|
665
|
+
reminderId: null,
|
|
666
|
+
source: "heuristic",
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
reminderPlan: {
|
|
670
|
+
steps: [
|
|
671
|
+
{
|
|
672
|
+
channel: "push",
|
|
673
|
+
offsetMinutes: 0,
|
|
674
|
+
label: "Alarm",
|
|
675
|
+
},
|
|
676
|
+
],
|
|
677
|
+
},
|
|
678
|
+
};
|
|
679
|
+
await client.createLifeOpsDefinition(request);
|
|
680
|
+
setShowAddAlarm(false);
|
|
681
|
+
await load();
|
|
682
|
+
}
|
|
683
|
+
catch (cause) {
|
|
684
|
+
setError(cause instanceof Error
|
|
685
|
+
? cause.message
|
|
686
|
+
: "Failed to create alarm.");
|
|
687
|
+
}
|
|
688
|
+
finally {
|
|
689
|
+
setSavingAlarm(false);
|
|
690
|
+
}
|
|
691
|
+
}, [load]);
|
|
692
|
+
return (_jsxs("div", { className: "space-y-4", "data-testid": "lifeops-reminders", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h2", { className: "text-base font-semibold tracking-tight text-txt", children: t("lifeopsreminders.title", { defaultValue: "Reminders" }) }), _jsx("span", { className: "rounded-full bg-bg-muted/40 px-2 py-0.5 text-[10px] font-medium text-muted tabular-nums", children: tab === "reminders" ? reminderCount : alarmEntries.length })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsx("button", { type: "button", className: "inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs text-muted transition-colors hover:bg-bg-muted/40 hover:text-txt disabled:opacity-40", onClick: () => void load(), disabled: loading, "aria-label": t("common.refresh", { defaultValue: "Refresh" }), children: _jsx(RefreshCw, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }) }) })] }), _jsxs("div", { role: "tablist", className: "inline-flex items-center gap-1 rounded-lg border border-border/15 bg-bg-muted/20 p-0.5 text-[11px] font-semibold", children: [_jsxs("button", { type: "button", role: "tab", "aria-selected": tab === "reminders", onClick: () => setTab("reminders"), className: [
|
|
693
|
+
"inline-flex items-center gap-1.5 rounded-md px-3 py-1 transition-colors",
|
|
694
|
+
tab === "reminders"
|
|
695
|
+
? "bg-card text-txt shadow-sm"
|
|
696
|
+
: "text-muted hover:text-txt",
|
|
697
|
+
].join(" "), children: [_jsx(Bell, { className: "h-3 w-3", "aria-hidden": true }), "Reminders", _jsx("span", { className: "rounded-full bg-bg-muted/50 px-1.5 text-[10px] tabular-nums text-muted", children: reminderCount })] }), _jsxs("button", { type: "button", role: "tab", "aria-selected": tab === "alarms", onClick: () => setTab("alarms"), className: [
|
|
698
|
+
"inline-flex items-center gap-1.5 rounded-md px-3 py-1 transition-colors",
|
|
699
|
+
tab === "alarms"
|
|
700
|
+
? "bg-card text-txt shadow-sm"
|
|
701
|
+
: "text-muted hover:text-txt",
|
|
702
|
+
].join(" "), children: [_jsx(AlarmClock, { className: "h-3 w-3", "aria-hidden": true }), "Alarms", _jsx("span", { className: "rounded-full bg-bg-muted/50 px-1.5 text-[10px] tabular-nums text-muted", children: alarmEntries.length })] })] }), error ? (_jsx("div", { className: "rounded-2xl border border-rose-500/30 bg-rose-500/10 px-3 py-2 text-xs text-rose-300", children: error })) : null, tab === "reminders" ? (_jsx(RemindersTabBody, { loading: loading, buckets: buckets, reminderCount: reminderCount, definitionById: definitionById, rowState: rowState, selection: selection, select: select, chatAboutReminder: chatAboutReminder, onSnooze: handleSnooze, onComplete: handleComplete, onCustomSnooze: handleCustomSnooze, loadingLabel: t("lifeopsreminders.loading", {
|
|
703
|
+
defaultValue: "Loading reminders…",
|
|
704
|
+
}), emptyLabel: t("lifeopsreminders.empty", {
|
|
705
|
+
defaultValue: "All clear. No active reminders.",
|
|
706
|
+
}) })) : (_jsx(AlarmsTabBody, { loading: loading, alarmEntries: alarmEntries, rowState: rowState, showAddAlarm: showAddAlarm, savingAlarm: savingAlarm, onSnooze: handleSnooze, onComplete: handleComplete, onCustomSnooze: handleCustomSnooze, onDelete: handleDeleteAlarm, onToggleAdd: () => setShowAddAlarm((prev) => !prev), onSaveAlarm: handleCreateAlarm, onCancelAdd: () => setShowAddAlarm(false) }))] }));
|
|
707
|
+
}
|
|
708
|
+
function RemindersTabBody({ loading, buckets, reminderCount, definitionById, rowState, selection, select, chatAboutReminder, onSnooze, onComplete, onCustomSnooze, loadingLabel, emptyLabel, }) {
|
|
709
|
+
if (loading && reminderCount === 0) {
|
|
710
|
+
return (_jsxs("div", { className: "flex items-center gap-2 py-6 text-xs text-muted", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), loadingLabel] }));
|
|
711
|
+
}
|
|
712
|
+
if (reminderCount === 0) {
|
|
713
|
+
return (_jsx("div", { className: "rounded-2xl border border-border/12 bg-card/12 px-4 py-10 text-center text-xs text-muted", children: emptyLabel }));
|
|
714
|
+
}
|
|
715
|
+
return (_jsx("div", { className: "space-y-4", children: BUCKET_ORDER.map((urgency) => {
|
|
716
|
+
const bucket = buckets[urgency];
|
|
717
|
+
if (bucket.length === 0)
|
|
718
|
+
return null;
|
|
719
|
+
return (_jsxs("div", { className: "space-y-1.5", children: [_jsx(BucketHeader, { urgency: urgency, count: bucket.length }), _jsx("div", { className: "overflow-hidden rounded-2xl border border-border/12 bg-card/12", children: bucket.map((reminder) => {
|
|
720
|
+
const rowKey = `${reminder.ownerType}:${reminder.ownerId}:${reminder.stepIndex}`;
|
|
721
|
+
const record = reminder.definitionId
|
|
722
|
+
? definitionById.get(reminder.definitionId)
|
|
723
|
+
: null;
|
|
724
|
+
const apple = readNativeAppleMetadata(record?.definition.metadata);
|
|
725
|
+
const recurrence = describeRecurrence(record?.definition.cadence);
|
|
726
|
+
const isSelected = selection.reminderId === reminder.ownerId;
|
|
727
|
+
const state = rowState[rowKey] ?? {
|
|
728
|
+
busy: null,
|
|
729
|
+
optimistic: "idle",
|
|
730
|
+
};
|
|
731
|
+
return (_jsx(ReminderRow, { reminder: reminder, urgency: urgency, isSelected: isSelected, apple: apple, recurrence: recurrence, busyAction: state.busy === "delete" ? null : state.busy, optimisticState: state.optimistic === "deleted"
|
|
732
|
+
? "idle"
|
|
733
|
+
: state.optimistic, onSelect: () => select({
|
|
734
|
+
reminderId: reminder.ownerId,
|
|
735
|
+
eventId: reminder.eventId ?? null,
|
|
736
|
+
}), onChat: () => chatAboutReminder(reminder), onSnooze: (option) => onSnooze(rowKey, reminder.occurrenceId, option), onComplete: () => onComplete(rowKey, reminder.occurrenceId), onCustomSnooze: () => onCustomSnooze(rowKey, reminder.occurrenceId) }, rowKey));
|
|
737
|
+
}) })] }, urgency));
|
|
738
|
+
}) }));
|
|
739
|
+
}
|
|
740
|
+
function AlarmsTabBody({ loading, alarmEntries, rowState, showAddAlarm, savingAlarm, onSnooze, onComplete, onCustomSnooze, onDelete, onToggleAdd, onSaveAlarm, onCancelAdd, }) {
|
|
741
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-[11px] text-muted", children: "Clock-time alarms. Mirrored to your native Apple Reminders on macOS." }), _jsxs("button", { type: "button", onClick: onToggleAdd, className: "inline-flex items-center gap-1 rounded-lg border border-border/15 bg-bg-muted/30 px-2 py-1 text-[11px] font-semibold text-muted transition-colors hover:bg-bg-muted/60 hover:text-txt", children: [_jsx(Plus, { className: "h-3 w-3", "aria-hidden": true }), showAddAlarm ? "Close" : "Add alarm"] })] }), showAddAlarm ? (_jsx(AddAlarmForm, { saving: savingAlarm, onSave: onSaveAlarm, onCancel: onCancelAdd })) : null, loading && alarmEntries.length === 0 ? (_jsxs("div", { className: "flex items-center gap-2 py-6 text-xs text-muted", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), "Loading alarms\u2026"] })) : null, !loading && alarmEntries.length === 0 ? (_jsx("div", { className: "rounded-2xl border border-border/12 bg-card/12 px-4 py-10 text-center text-xs text-muted", children: "No alarms yet. Click \u201CAdd alarm\u201D to schedule one." })) : null, alarmEntries.length > 0 ? (_jsx("div", { className: "space-y-2", children: alarmEntries.map((entry) => {
|
|
742
|
+
const rowKey = `alarm:${entry.definition.id}`;
|
|
743
|
+
const state = rowState[rowKey] ?? {
|
|
744
|
+
busy: null,
|
|
745
|
+
optimistic: "idle",
|
|
746
|
+
};
|
|
747
|
+
return (_jsx(AlarmRow, { entry: entry, busyAction: state.busy, optimisticState: state.optimistic, onSnooze: (option) => onSnooze(rowKey, entry.reminder?.occurrenceId ?? null, option), onComplete: () => onComplete(rowKey, entry.reminder?.occurrenceId ?? null), onCustomSnooze: () => onCustomSnooze(rowKey, entry.reminder?.occurrenceId ?? null), onDelete: () => onDelete(entry.definition.id) }, entry.definition.id));
|
|
748
|
+
}) })) : null] }));
|
|
749
|
+
}
|