@agent-relay/dashboard 2.0.83-beta.0 → 2.0.85

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.
Files changed (228) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/{TnAI-TAQ4-bNJRL3Ln3NB → 49XhcS8k_e8607S7KBMwA}/_buildManifest.js +1 -1
  3. package/out/_next/static/chunks/1028-53c5a7e2453505f8.js +1 -0
  4. package/out/_next/static/chunks/1528-78b17000a7e10bc6.js +2 -0
  5. package/out/_next/static/chunks/1695-4a5d33ba715e09b4.js +1 -0
  6. package/out/_next/static/chunks/1705-36c2180d00a4a569.js +1 -0
  7. package/out/_next/static/chunks/1dd3208c-e1f87c7b3dc1a820.js +1 -0
  8. package/out/_next/static/chunks/3663-47290254b8f6f5dd.js +1 -0
  9. package/out/_next/static/chunks/3677-4b225baf4801d9b9.js +73 -0
  10. package/out/_next/static/chunks/5118-de1c8f968feab8e2.js +1 -0
  11. package/out/_next/static/chunks/5888-15cbe97c90ed5fae.js +1 -0
  12. package/out/_next/static/chunks/6773-a45343a98df3abb5.js +1 -0
  13. package/out/_next/static/chunks/6940-b824612b605e79b3.js +9 -0
  14. package/out/_next/static/chunks/7894-f4a15249082a680d.js +1 -0
  15. package/out/_next/static/chunks/9175-b3617c1e5cbfed0e.js +1 -0
  16. package/out/_next/static/chunks/9372-1a804b8d08c7a236.js +1 -0
  17. package/out/_next/static/chunks/{ab6c8a12-0a58072fbb505134.js → ab6c8a12-91438a812d94ecf0.js} +1 -1
  18. package/out/_next/static/chunks/app/_not-found/page-8e8842f82d204726.js +1 -0
  19. package/out/_next/static/chunks/app/about/page-b78577a7da8fa459.js +1 -0
  20. package/out/_next/static/chunks/app/app/[[...slug]]/page-3dffd65b6344f53e.js +1 -0
  21. package/out/_next/static/chunks/app/app/onboarding/page-b89be9aa6264a5e1.js +1 -0
  22. package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-fbd00893ef69e499.js +1 -0
  23. package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-de2ea13649d0b6d3.js +1 -0
  24. package/out/_next/static/chunks/app/blog/page-a08e263c57a156fa.js +1 -0
  25. package/out/_next/static/chunks/app/careers/page-02228e1d6969b232.js +1 -0
  26. package/out/_next/static/chunks/app/changelog/page-1b5c1d79efc6e53a.js +1 -0
  27. package/out/_next/static/chunks/app/cloud/link/page-99654edffffb3af2.js +1 -0
  28. package/out/_next/static/chunks/app/complete-profile/page-59d146e5ddeafc5c.js +1 -0
  29. package/out/_next/static/chunks/app/connect-repos/page-995e16a976a6632c.js +1 -0
  30. package/out/_next/static/chunks/app/contact/page-273396a5ad57bcee.js +1 -0
  31. package/out/_next/static/chunks/app/dev/cli-tools/page-a71b80dcb2d5fc8d.js +1 -0
  32. package/out/_next/static/chunks/app/dev/log-viewer/page-46a6151ae1be0796.js +1 -0
  33. package/out/_next/static/chunks/app/docs/page-7c7cb603b24b7c40.js +1 -0
  34. package/out/_next/static/chunks/app/history/page-0c5cab1dab4e8886.js +1 -0
  35. package/out/_next/static/chunks/app/layout-96d72ba8ef8a43a0.js +1 -0
  36. package/out/_next/static/chunks/app/login/page-0ccbab34213df842.js +1 -0
  37. package/out/_next/static/chunks/app/metrics/page-8616272aeab9c8b0.js +1 -0
  38. package/out/_next/static/chunks/app/page-09ce10603ad9a251.js +1 -0
  39. package/out/_next/static/chunks/app/pricing/page-91c975079120c941.js +1 -0
  40. package/out/_next/static/chunks/app/privacy/{page-c21d51ac2dee3a88.js → page-a49ab271cc686644.js} +1 -1
  41. package/out/_next/static/chunks/app/providers/{page-59114505f4353512.js → page-d775d6eb5bc29e96.js} +1 -1
  42. package/out/_next/static/chunks/app/providers/setup/[provider]/page-ec4ef3cd80de807e.js +1 -0
  43. package/out/_next/static/chunks/app/security/page-d9da9bd9191e8f95.js +1 -0
  44. package/out/_next/static/chunks/app/signup/page-930eca0bf5fd299d.js +1 -0
  45. package/out/_next/static/chunks/app/terms/page-3e4827620b98613c.js +1 -0
  46. package/out/_next/static/chunks/framework-648e1ae7da590300.js +1 -0
  47. package/out/_next/static/chunks/{main-acb1b24265295d6a.js → main-2b1990080c292d92.js} +1 -1
  48. package/out/_next/static/chunks/main-app-9f6b7ff9e754a8f5.js +1 -0
  49. package/out/_next/static/chunks/pages/_app-a077b72e02273ab1.js +1 -0
  50. package/out/_next/static/chunks/pages/_error-84001666436a04e4.js +1 -0
  51. package/out/_next/static/chunks/{webpack-dd93b81e2659669c.js → webpack-7586035f1585f2db.js} +1 -1
  52. package/out/_next/static/css/eb9fc69d1e3d2bed.css +1 -0
  53. package/out/about.html +2 -2
  54. package/out/about.txt +2 -2
  55. package/out/app/onboarding.html +1 -1
  56. package/out/app/onboarding.txt +2 -2
  57. package/out/app.html +1 -1
  58. package/out/app.txt +2 -2
  59. package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +3 -3
  60. package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
  61. package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
  62. package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
  63. package/out/blog.html +2 -2
  64. package/out/blog.txt +1 -1
  65. package/out/careers.html +2 -2
  66. package/out/careers.txt +2 -2
  67. package/out/changelog.html +2 -2
  68. package/out/changelog.txt +2 -2
  69. package/out/cloud/link.html +1 -1
  70. package/out/cloud/link.txt +2 -2
  71. package/out/complete-profile.html +2 -2
  72. package/out/complete-profile.txt +2 -2
  73. package/out/connect-repos.html +1 -1
  74. package/out/connect-repos.txt +2 -2
  75. package/out/contact.html +2 -2
  76. package/out/contact.txt +2 -2
  77. package/out/dev/cli-tools.html +1 -0
  78. package/out/dev/cli-tools.txt +7 -0
  79. package/out/dev/log-viewer.html +23 -0
  80. package/out/dev/log-viewer.txt +7 -0
  81. package/out/docs.html +2 -2
  82. package/out/docs.txt +2 -2
  83. package/out/history.html +1 -1
  84. package/out/history.txt +2 -2
  85. package/out/index.html +1 -1
  86. package/out/index.txt +2 -2
  87. package/out/login.html +2 -2
  88. package/out/login.txt +2 -2
  89. package/out/metrics.html +1 -1
  90. package/out/metrics.txt +2 -2
  91. package/out/pricing.html +2 -2
  92. package/out/pricing.txt +2 -2
  93. package/out/privacy.html +2 -2
  94. package/out/privacy.txt +2 -2
  95. package/out/providers/setup/claude.html +1 -1
  96. package/out/providers/setup/claude.txt +2 -2
  97. package/out/providers/setup/codex.html +1 -1
  98. package/out/providers/setup/codex.txt +2 -2
  99. package/out/providers/setup/cursor.html +1 -1
  100. package/out/providers/setup/cursor.txt +2 -2
  101. package/out/providers.html +1 -1
  102. package/out/providers.txt +2 -2
  103. package/out/security.html +2 -2
  104. package/out/security.txt +2 -2
  105. package/out/signup.html +2 -2
  106. package/out/signup.txt +2 -2
  107. package/out/terms.html +2 -2
  108. package/out/terms.txt +2 -2
  109. package/package.json +5 -1
  110. package/src/adapters/DashboardConfigProvider.tsx +56 -0
  111. package/src/adapters/cloudFetchAdapter.ts +278 -0
  112. package/src/adapters/index.ts +3 -0
  113. package/src/adapters/types.ts +508 -0
  114. package/src/app/app/[[...slug]]/DashboardPageClient.tsx +67 -18
  115. package/src/app/app/onboarding/page.tsx +870 -170
  116. package/src/app/cloud/link/page.tsx +14 -6
  117. package/src/app/connect-repos/page.tsx +9 -3
  118. package/src/app/dev/cli-tools/page.tsx +130 -0
  119. package/src/app/dev/log-viewer/MockLogViewer.tsx +132 -0
  120. package/src/app/dev/log-viewer/fixtures.ts +110 -0
  121. package/src/app/dev/log-viewer/page.tsx +288 -0
  122. package/src/app/history/page.tsx +28 -12
  123. package/src/app/page.tsx +1 -1
  124. package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +209 -59
  125. package/src/components/AgentCard.tsx +4 -4
  126. package/src/components/AgentLogPreview.tsx +2 -38
  127. package/src/components/App.tsx +441 -2624
  128. package/src/components/CliToolHarness.test.tsx +83 -0
  129. package/src/components/CliToolHarness.tsx +292 -0
  130. package/src/components/CoordinatorPanel.tsx +13 -6
  131. package/src/components/LogViewer.tsx +2 -42
  132. package/src/components/ProviderAuthFlow.tsx +201 -81
  133. package/src/components/ProvisioningProgress.tsx +1 -1
  134. package/src/components/ReactionChips.tsx +2 -1
  135. package/src/components/SpawnModal.test.tsx +51 -18
  136. package/src/components/SpawnModal.tsx +175 -207
  137. package/src/components/TerminalProviderSetup.tsx +1 -1
  138. package/src/components/ThreadPanel.tsx +2 -0
  139. package/src/components/WorkspaceContext.tsx +7 -19
  140. package/src/components/XTermLogViewer.tsx +190 -27
  141. package/src/components/channels/ChannelMessageList.tsx +94 -4
  142. package/src/components/channels/ChannelViewV1.tsx +35 -11
  143. package/src/components/channels/api.ts +21 -20
  144. package/src/components/channels/types.ts +16 -0
  145. package/src/components/hooks/index.ts +0 -19
  146. package/src/components/hooks/useMessages.test.ts +80 -0
  147. package/src/components/hooks/useMessages.ts +21 -9
  148. package/src/components/hooks/useOrchestrator.ts +1 -1
  149. package/src/components/hooks/usePresence.ts +45 -6
  150. package/src/components/hooks/useThread.ts +86 -47
  151. package/src/components/hooks/useTrajectory.ts +62 -5
  152. package/src/components/hooks/useWebSocket.test.ts +358 -0
  153. package/src/components/hooks/useWebSocket.ts +243 -5
  154. package/src/components/index.ts +2 -14
  155. package/src/components/layout/Header.tsx +9 -15
  156. package/src/components/layout/Sidebar.tsx +1 -8
  157. package/src/components/settings/SettingsPage.tsx +108 -47
  158. package/src/components/settings/index.ts +0 -3
  159. package/src/landing/blogData.ts +1 -1
  160. package/src/lib/agent-merge.test.ts +2 -2
  161. package/src/lib/api.ts +12 -39
  162. package/src/lib/identity.test.ts +139 -0
  163. package/src/lib/identity.ts +48 -0
  164. package/src/lib/relaycastMessageAdapters.test.ts +182 -0
  165. package/src/lib/relaycastMessageAdapters.ts +105 -0
  166. package/src/lib/sanitize-logs.test.ts +227 -0
  167. package/src/lib/sanitize-logs.ts +202 -0
  168. package/src/providers/AgentProvider.tsx +799 -0
  169. package/src/providers/ChannelProvider.tsx +528 -0
  170. package/src/providers/CloudWorkspaceProvider.tsx +402 -0
  171. package/src/providers/MessageProvider.tsx +875 -0
  172. package/src/providers/RelayConfigProvider.tsx +94 -0
  173. package/src/providers/SendProvider.tsx +497 -0
  174. package/src/providers/SettingsProvider.tsx +247 -0
  175. package/src/providers/index.ts +26 -0
  176. package/src/types/index.ts +10 -10
  177. package/out/_next/static/chunks/11-9a2993a37266dcb3.js +0 -9
  178. package/out/_next/static/chunks/118-ae2b650136a5a5fc.js +0 -1
  179. package/out/_next/static/chunks/1dd3208c-40ab0fc0f60392b8.js +0 -1
  180. package/out/_next/static/chunks/202-fc0763dd7488e58f.js +0 -1
  181. package/out/_next/static/chunks/259-83b77fa1b91ba5aa.js +0 -1
  182. package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +0 -1
  183. package/out/_next/static/chunks/528-f5f676996d613c25.js +0 -2
  184. package/out/_next/static/chunks/663-ddb04081febc3678.js +0 -1
  185. package/out/_next/static/chunks/687-88b6b139a6bb0e2e.js +0 -1
  186. package/out/_next/static/chunks/695-51d25b1988644374.js +0 -1
  187. package/out/_next/static/chunks/773-54a2641043c81e55.js +0 -1
  188. package/out/_next/static/chunks/app/_not-found/page-6da9b72091e5b511.js +0 -1
  189. package/out/_next/static/chunks/app/about/page-fff7c6457683f243.js +0 -1
  190. package/out/_next/static/chunks/app/app/[[...slug]]/page-f7eca1b66fb4249b.js +0 -1
  191. package/out/_next/static/chunks/app/app/onboarding/page-129abc5da2e67971.js +0 -1
  192. package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-5d5f28fd126b692f.js +0 -1
  193. package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-b194f207fbd91862.js +0 -1
  194. package/out/_next/static/chunks/app/blog/page-b9bd9d8703fca76a.js +0 -1
  195. package/out/_next/static/chunks/app/careers/page-a4bd8d5f4de8f4eb.js +0 -1
  196. package/out/_next/static/chunks/app/changelog/page-9a1f6ad1743d63c5.js +0 -1
  197. package/out/_next/static/chunks/app/cloud/link/page-0844c5699b027c3b.js +0 -1
  198. package/out/_next/static/chunks/app/complete-profile/page-39ed5a67916beb87.js +0 -1
  199. package/out/_next/static/chunks/app/connect-repos/page-297eddee0c39f2a3.js +0 -1
  200. package/out/_next/static/chunks/app/contact/page-3c1dd8690217fade.js +0 -1
  201. package/out/_next/static/chunks/app/docs/page-1875e981f2c3fd13.js +0 -1
  202. package/out/_next/static/chunks/app/history/page-2d5c5695c9e8b40c.js +0 -1
  203. package/out/_next/static/chunks/app/layout-0a4b99656da25511.js +0 -1
  204. package/out/_next/static/chunks/app/login/page-f69c076f5a6fc520.js +0 -1
  205. package/out/_next/static/chunks/app/metrics/page-bebbee055669a17e.js +0 -1
  206. package/out/_next/static/chunks/app/page-0ee604f7070d14c0.js +0 -1
  207. package/out/_next/static/chunks/app/pricing/page-eeae7d594af333b6.js +0 -1
  208. package/out/_next/static/chunks/app/providers/setup/[provider]/page-daf9b3e05e77ae19.js +0 -1
  209. package/out/_next/static/chunks/app/security/page-cd562730fe84a0a2.js +0 -1
  210. package/out/_next/static/chunks/app/signup/page-c242ca08101a84ff.js +0 -1
  211. package/out/_next/static/chunks/app/terms/page-c7001720e7941dc6.js +0 -1
  212. package/out/_next/static/chunks/framework-3664cab31236a9fa.js +0 -1
  213. package/out/_next/static/chunks/main-app-7f73a939a312a228.js +0 -1
  214. package/out/_next/static/chunks/pages/_app-10a93ab5b7c32eb3.js +0 -1
  215. package/out/_next/static/chunks/pages/_error-2d792b2a41857be4.js +0 -1
  216. package/out/_next/static/css/8968d98ed4c4d33f.css +0 -1
  217. package/src/components/BillingResult.tsx +0 -447
  218. package/src/components/CloudSessionProvider.tsx +0 -130
  219. package/src/components/SessionExpiredModal.tsx +0 -128
  220. package/src/components/WorkspaceStatusIndicator.tsx +0 -396
  221. package/src/components/hooks/useSession.ts +0 -209
  222. package/src/components/hooks/useWorkspaceMembers.ts +0 -132
  223. package/src/components/hooks/useWorkspaceStatus.ts +0 -237
  224. package/src/components/settings/BillingSettingsPanel.tsx +0 -564
  225. package/src/components/settings/TeamSettingsPanel.tsx +0 -560
  226. package/src/components/settings/WorkspaceSettingsPanel.tsx +0 -1368
  227. package/src/lib/cloudApi.ts +0 -893
  228. /package/out/_next/static/{TnAI-TAQ4-bNJRL3Ln3NB → 49XhcS8k_e8607S7KBMwA}/_ssgManifest.js +0 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Settings Provider
3
+ *
4
+ * Manages user preferences: theme, display options, notification settings.
5
+ * Persists to localStorage and applies theme to the document root.
6
+ */
7
+
8
+ import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
9
+ import { defaultSettings, type Settings } from '../components/settings';
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Types
13
+ // ---------------------------------------------------------------------------
14
+
15
+ type LegacyDashboardSettings = {
16
+ theme?: 'dark' | 'light' | 'system';
17
+ compactMode?: boolean;
18
+ showTimestamps?: boolean;
19
+ soundEnabled?: boolean;
20
+ notificationsEnabled?: boolean;
21
+ autoScrollMessages?: boolean;
22
+ };
23
+
24
+ interface SettingsContextValue {
25
+ settings: Settings;
26
+ updateSettings: (updater: (prev: Settings) => Settings) => void;
27
+ }
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Constants
31
+ // ---------------------------------------------------------------------------
32
+
33
+ const SETTINGS_STORAGE_KEY = 'dashboard-settings';
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Helpers
37
+ // ---------------------------------------------------------------------------
38
+
39
+ function mergeSettings(base: Settings, partial: Partial<Settings>): Settings {
40
+ return {
41
+ ...base,
42
+ ...partial,
43
+ notifications: { ...base.notifications, ...partial.notifications },
44
+ display: { ...base.display, ...partial.display },
45
+ messages: { ...base.messages, ...partial.messages },
46
+ connection: { ...base.connection, ...partial.connection },
47
+ agentDefaults: {
48
+ ...base.agentDefaults,
49
+ ...partial.agentDefaults,
50
+ defaultModels: {
51
+ ...base.agentDefaults?.defaultModels,
52
+ ...partial.agentDefaults?.defaultModels,
53
+ },
54
+ },
55
+ };
56
+ }
57
+
58
+ function migrateLegacySettings(raw: LegacyDashboardSettings): Settings {
59
+ const theme = raw.theme && ['dark', 'light', 'system'].includes(raw.theme)
60
+ ? raw.theme
61
+ : defaultSettings.theme;
62
+ const sound = raw.soundEnabled ?? defaultSettings.notifications.sound;
63
+ const desktop = raw.notificationsEnabled ?? defaultSettings.notifications.desktop;
64
+ return {
65
+ ...defaultSettings,
66
+ theme,
67
+ display: {
68
+ ...defaultSettings.display,
69
+ compactMode: raw.compactMode ?? defaultSettings.display.compactMode,
70
+ showTimestamps: raw.showTimestamps ?? defaultSettings.display.showTimestamps,
71
+ },
72
+ notifications: {
73
+ ...defaultSettings.notifications,
74
+ sound,
75
+ desktop,
76
+ enabled: sound || desktop || defaultSettings.notifications.mentionsOnly,
77
+ },
78
+ messages: {
79
+ ...defaultSettings.messages,
80
+ autoScroll: raw.autoScrollMessages ?? defaultSettings.messages.autoScroll,
81
+ },
82
+ };
83
+ }
84
+
85
+ function loadSettingsFromStorage(): Settings {
86
+ if (typeof window === 'undefined') return defaultSettings;
87
+ try {
88
+ const saved = localStorage.getItem(SETTINGS_STORAGE_KEY);
89
+ if (!saved) return defaultSettings;
90
+ const parsed = JSON.parse(saved);
91
+ if (!parsed || typeof parsed !== 'object') return defaultSettings;
92
+ if ('notifications' in parsed && 'display' in parsed) {
93
+ const merged = mergeSettings(defaultSettings, parsed as Partial<Settings>);
94
+ merged.notifications.enabled = merged.notifications.sound ||
95
+ merged.notifications.desktop ||
96
+ merged.notifications.mentionsOnly;
97
+ return merged;
98
+ }
99
+ if ('notificationsEnabled' in parsed || 'soundEnabled' in parsed || 'autoScrollMessages' in parsed) {
100
+ return migrateLegacySettings(parsed as LegacyDashboardSettings);
101
+ }
102
+ } catch {
103
+ // Fall back to defaults
104
+ }
105
+ return defaultSettings;
106
+ }
107
+
108
+ function saveSettingsToStorage(settings: Settings) {
109
+ if (typeof window === 'undefined') return;
110
+ try {
111
+ localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
112
+ } catch {
113
+ // Ignore localStorage failures
114
+ }
115
+ }
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // Context
119
+ // ---------------------------------------------------------------------------
120
+
121
+ const SettingsContext = createContext<SettingsContextValue | null>(null);
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // Provider
125
+ // ---------------------------------------------------------------------------
126
+
127
+ export interface SettingsProviderProps {
128
+ children: React.ReactNode;
129
+ }
130
+
131
+ export function SettingsProvider({ children }: SettingsProviderProps) {
132
+ const [settings, setSettings] = useState<Settings>(() => loadSettingsFromStorage());
133
+
134
+ const updateSettings = useCallback((updater: (prev: Settings) => Settings) => {
135
+ setSettings((prev) => updater(prev));
136
+ }, []);
137
+
138
+ // Persist settings changes
139
+ useEffect(() => {
140
+ saveSettingsToStorage(settings);
141
+ }, [settings]);
142
+
143
+ // Apply theme to document
144
+ useEffect(() => {
145
+ const applyTheme = (theme: 'light' | 'dark' | 'system') => {
146
+ let effectiveTheme: 'light' | 'dark';
147
+
148
+ if (theme === 'system') {
149
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
150
+ effectiveTheme = prefersDark ? 'dark' : 'light';
151
+ } else {
152
+ effectiveTheme = theme;
153
+ }
154
+
155
+ const root = document.documentElement;
156
+ root.classList.remove('theme-light', 'theme-dark');
157
+ root.classList.add(`theme-${effectiveTheme}`);
158
+ root.style.colorScheme = effectiveTheme;
159
+ };
160
+
161
+ applyTheme(settings.theme);
162
+
163
+ if (settings.theme === 'system') {
164
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
165
+ const handleChange = () => applyTheme('system');
166
+ mediaQuery.addEventListener('change', handleChange);
167
+ return () => mediaQuery.removeEventListener('change', handleChange);
168
+ }
169
+ }, [settings.theme]);
170
+
171
+ // Request browser notification permissions when enabled
172
+ useEffect(() => {
173
+ if (!settings.notifications.desktop) return;
174
+ if (typeof window === 'undefined' || !('Notification' in window)) return;
175
+
176
+ if (Notification.permission === 'granted') return;
177
+
178
+ if (Notification.permission === 'denied') {
179
+ updateSettings((prev) => ({
180
+ ...prev,
181
+ notifications: {
182
+ ...prev.notifications,
183
+ desktop: false,
184
+ enabled: prev.notifications.sound || prev.notifications.mentionsOnly,
185
+ },
186
+ }));
187
+ return;
188
+ }
189
+
190
+ Notification.requestPermission().then((permission) => {
191
+ if (permission !== 'granted') {
192
+ updateSettings((prev) => ({
193
+ ...prev,
194
+ notifications: {
195
+ ...prev.notifications,
196
+ desktop: false,
197
+ enabled: prev.notifications.sound || prev.notifications.mentionsOnly,
198
+ },
199
+ }));
200
+ }
201
+ }).catch(() => undefined);
202
+ }, [settings.notifications.desktop, settings.notifications.sound, settings.notifications.mentionsOnly, updateSettings]);
203
+
204
+ return (
205
+ <SettingsContext.Provider value={{ settings, updateSettings }}>
206
+ {children}
207
+ </SettingsContext.Provider>
208
+ );
209
+ }
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // Hook
213
+ // ---------------------------------------------------------------------------
214
+
215
+ export function useSettings(): SettingsContextValue {
216
+ const ctx = useContext(SettingsContext);
217
+ if (!ctx) {
218
+ throw new Error('useSettings must be used within a SettingsProvider');
219
+ }
220
+ return ctx;
221
+ }
222
+
223
+ // Re-export the notification sound helper so App can still use it
224
+ export function playNotificationSound() {
225
+ if (typeof window === 'undefined') return;
226
+ const AudioContextConstructor =
227
+ window.AudioContext ||
228
+ (window as Window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;
229
+ if (!AudioContextConstructor) return;
230
+ try {
231
+ const context = new AudioContextConstructor();
232
+ const oscillator = context.createOscillator();
233
+ const gain = context.createGain();
234
+ oscillator.type = 'sine';
235
+ oscillator.frequency.value = 880;
236
+ gain.gain.value = 0.03;
237
+ oscillator.connect(gain);
238
+ gain.connect(context.destination);
239
+ oscillator.start();
240
+ oscillator.stop(context.currentTime + 0.12);
241
+ oscillator.onended = () => {
242
+ context.close().catch(() => undefined);
243
+ };
244
+ } catch {
245
+ // Audio might be blocked by browser autoplay policies
246
+ }
247
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Provider exports
3
+ *
4
+ * Focused context providers extracted from the monolithic App component.
5
+ */
6
+
7
+ export { SettingsProvider, useSettings, playNotificationSound } from './SettingsProvider';
8
+ export type { SettingsProviderProps } from './SettingsProvider';
9
+
10
+ export { CloudWorkspaceProvider, useCloudWorkspace } from './CloudWorkspaceProvider';
11
+ export type { CloudWorkspaceProviderProps, CloudWorkspace } from './CloudWorkspaceProvider';
12
+
13
+ export { RelayConfigProvider } from './RelayConfigProvider';
14
+ export type { RelayConfigProviderProps } from './RelayConfigProvider';
15
+
16
+ export { AgentProvider, useAgentContext } from './AgentProvider';
17
+ export type { AgentProviderProps } from './AgentProvider';
18
+
19
+ export { MessageProvider, useMessageContext, ACTIVITY_FEED_ID } from './MessageProvider';
20
+ export type { MessageProviderProps } from './MessageProvider';
21
+
22
+ export { ChannelProvider, useChannelContext } from './ChannelProvider';
23
+ export type { ChannelProviderProps, ChannelContextValue } from './ChannelProvider';
24
+
25
+ export { SendProvider, useSendContext } from './SendProvider';
26
+ export type { SendProviderProps, SendContextValue } from './SendProvider';
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type { AgentStatus } from '../lib/colors';
6
6
  import type { ThreadMetadata } from './threading';
7
+ import type { ReactionGroup } from '@relaycast/types';
7
8
 
8
9
  export type { ThreadMetadata } from './threading';
9
10
 
@@ -22,6 +23,7 @@ export interface Agent {
22
23
  server?: string; // For fleet view - which server the agent is on
23
24
  isProcessing?: boolean; // True when agent is thinking/processing a message
24
25
  processingStartedAt?: number; // Timestamp when processing started
26
+ lastLogLine?: string; // Last log output line from worker_stream
25
27
  isSpawned?: boolean; // True if agent was spawned via dashboard (can be killed)
26
28
  team?: string; // Optional user-defined team grouping (e.g., "frontend-team", "backend-team")
27
29
  agentId?: string; // Unique agent ID for resume functionality
@@ -32,10 +34,10 @@ export interface Agent {
32
34
  avatarUrl?: string; // Avatar URL for human users
33
35
  authRevoked?: boolean; // True if agent's authentication has been revoked (needs re-login)
34
36
  cwd?: string; // Working directory (repo name) the agent was spawned in
35
- // Local daemon agent fields
36
- isLocal?: boolean; // True if agent is from a linked local daemon
37
- daemonName?: string; // Name of the linked daemon
38
- machineId?: string; // Machine ID of the linked daemon
37
+ // Local broker agent fields
38
+ isLocal?: boolean; // True if agent is from a linked local broker
39
+ brokerName?: string; // Name of the linked broker
40
+ machineId?: string; // Machine ID of the linked broker
39
41
  // Profile fields for understanding agent behavior
40
42
  profile?: AgentProfile;
41
43
  }
@@ -101,12 +103,8 @@ export interface Attachment {
101
103
  }
102
104
 
103
105
 
104
- // Reaction Types
105
- export interface Reaction {
106
- emoji: string;
107
- count: number;
108
- agents: string[];
109
- }
106
+ // Reaction Types — sourced from canonical @relaycast/types
107
+ export type Reaction = ReactionGroup;
110
108
 
111
109
  // Message Types
112
110
  export interface Message {
@@ -279,6 +277,8 @@ export interface SpawnAgentRequest {
279
277
  shadowTriggers?: SpeakOnTrigger[];
280
278
  /** When the shadow should speak */
281
279
  shadowSpeakOn?: SpeakOnTrigger[];
280
+ /** Agent name to continue session from (agent continuity) */
281
+ continueFrom?: string;
282
282
  }
283
283
 
284
284
  export interface SpawnAgentResponse {