cowork-os 0.3.21 → 0.3.25

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 (252) hide show
  1. package/README.md +372 -10
  2. package/connectors/README.md +20 -0
  3. package/connectors/asana-mcp/README.md +24 -0
  4. package/connectors/asana-mcp/dist/index.js +427 -0
  5. package/connectors/asana-mcp/package.json +15 -0
  6. package/connectors/asana-mcp/src/index.ts +553 -0
  7. package/connectors/asana-mcp/tsconfig.json +13 -0
  8. package/connectors/hubspot-mcp/README.md +35 -0
  9. package/connectors/hubspot-mcp/dist/index.js +454 -0
  10. package/connectors/hubspot-mcp/package.json +15 -0
  11. package/connectors/hubspot-mcp/src/index.ts +562 -0
  12. package/connectors/hubspot-mcp/tsconfig.json +13 -0
  13. package/connectors/jira-mcp/README.md +49 -0
  14. package/connectors/jira-mcp/dist/index.js +588 -0
  15. package/connectors/jira-mcp/package.json +15 -0
  16. package/connectors/jira-mcp/src/index.ts +711 -0
  17. package/connectors/jira-mcp/tsconfig.json +13 -0
  18. package/connectors/linear-mcp/README.md +22 -0
  19. package/connectors/linear-mcp/dist/index.js +402 -0
  20. package/connectors/linear-mcp/package.json +15 -0
  21. package/connectors/linear-mcp/src/index.ts +522 -0
  22. package/connectors/linear-mcp/tsconfig.json +13 -0
  23. package/connectors/okta-mcp/README.md +24 -0
  24. package/connectors/okta-mcp/dist/index.js +411 -0
  25. package/connectors/okta-mcp/package.json +15 -0
  26. package/connectors/okta-mcp/src/index.ts +520 -0
  27. package/connectors/okta-mcp/tsconfig.json +13 -0
  28. package/connectors/salesforce-mcp/README.md +47 -0
  29. package/connectors/salesforce-mcp/dist/index.js +584 -0
  30. package/connectors/salesforce-mcp/package.json +15 -0
  31. package/connectors/salesforce-mcp/src/index.ts +722 -0
  32. package/connectors/salesforce-mcp/tsconfig.json +13 -0
  33. package/connectors/servicenow-mcp/README.md +26 -0
  34. package/connectors/servicenow-mcp/dist/index.js +400 -0
  35. package/connectors/servicenow-mcp/package.json +15 -0
  36. package/connectors/servicenow-mcp/src/index.ts +500 -0
  37. package/connectors/servicenow-mcp/tsconfig.json +13 -0
  38. package/connectors/templates/mcp-connector/README.md +31 -0
  39. package/connectors/templates/mcp-connector/package.json +15 -0
  40. package/connectors/templates/mcp-connector/src/index.ts +330 -0
  41. package/connectors/templates/mcp-connector/tsconfig.json +13 -0
  42. package/connectors/zendesk-mcp/README.md +40 -0
  43. package/connectors/zendesk-mcp/dist/index.js +431 -0
  44. package/connectors/zendesk-mcp/package.json +15 -0
  45. package/connectors/zendesk-mcp/src/index.ts +543 -0
  46. package/connectors/zendesk-mcp/tsconfig.json +13 -0
  47. package/dist/electron/electron/agent/custom-skill-loader.js +31 -1
  48. package/dist/electron/electron/agent/daemon.js +189 -13
  49. package/dist/electron/electron/agent/executor.js +895 -78
  50. package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
  51. package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
  52. package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
  53. package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
  54. package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
  55. package/dist/electron/electron/agent/llm/index.js +13 -1
  56. package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
  57. package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
  58. package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
  59. package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
  60. package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
  61. package/dist/electron/electron/agent/llm/provider-factory.js +350 -4
  62. package/dist/electron/electron/agent/llm/types.js +66 -1
  63. package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
  64. package/dist/electron/electron/agent/search/provider-factory.js +38 -2
  65. package/dist/electron/electron/agent/tools/box-tools.js +231 -0
  66. package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
  67. package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
  68. package/dist/electron/electron/agent/tools/file-tools.js +66 -3
  69. package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
  70. package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
  71. package/dist/electron/electron/agent/tools/image-tools.js +11 -1
  72. package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
  73. package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
  74. package/dist/electron/electron/agent/tools/registry.js +548 -10
  75. package/dist/electron/electron/agent/tools/search-tools.js +28 -10
  76. package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
  77. package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
  78. package/dist/electron/electron/agent/tools/x-tools.js +1 -1
  79. package/dist/electron/electron/agents/agent-dispatch.js +63 -0
  80. package/dist/electron/electron/database/repositories.js +19 -5
  81. package/dist/electron/electron/database/schema.js +8 -0
  82. package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
  83. package/dist/electron/electron/gateway/index.js +75 -1
  84. package/dist/electron/electron/gateway/router.js +209 -154
  85. package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
  86. package/dist/electron/electron/ipc/handlers.js +763 -267
  87. package/dist/electron/electron/main.js +63 -0
  88. package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
  89. package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
  90. package/dist/electron/electron/memory/MemoryService.js +2 -1
  91. package/dist/electron/electron/preload.js +78 -1
  92. package/dist/electron/electron/settings/appearance-manager.js +18 -1
  93. package/dist/electron/electron/settings/box-manager.js +54 -0
  94. package/dist/electron/electron/settings/dropbox-manager.js +54 -0
  95. package/dist/electron/electron/settings/google-drive-manager.js +54 -0
  96. package/dist/electron/electron/settings/notion-manager.js +56 -0
  97. package/dist/electron/electron/settings/onedrive-manager.js +54 -0
  98. package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
  99. package/dist/electron/electron/utils/box-api.js +153 -0
  100. package/dist/electron/electron/utils/dropbox-api.js +144 -0
  101. package/dist/electron/electron/utils/env-migration.js +19 -0
  102. package/dist/electron/electron/utils/google-drive-api.js +152 -0
  103. package/dist/electron/electron/utils/notion-api.js +103 -0
  104. package/dist/electron/electron/utils/onedrive-api.js +113 -0
  105. package/dist/electron/electron/utils/sharepoint-api.js +109 -0
  106. package/dist/electron/electron/utils/validation.js +98 -3
  107. package/dist/electron/electron/utils/x-cli.js +1 -1
  108. package/dist/electron/shared/channelMessages.js +284 -3
  109. package/dist/electron/shared/llm-provider-catalog.js +198 -0
  110. package/dist/electron/shared/types.js +90 -1
  111. package/package.json +14 -3
  112. package/resources/skills/nano-banana-pro.json +4 -4
  113. package/resources/skills/openai-image-gen.json +3 -3
  114. package/resources/skills/scripts/gen.py +163 -0
  115. package/resources/skills/scripts/generate_image.py +91 -0
  116. package/src/electron/agent/custom-skill-loader.ts +34 -1
  117. package/src/electron/agent/daemon.ts +210 -14
  118. package/src/electron/agent/executor.ts +1124 -85
  119. package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
  120. package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
  121. package/src/electron/agent/llm/bedrock-provider.ts +62 -9
  122. package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
  123. package/src/electron/agent/llm/groq-provider.ts +39 -0
  124. package/src/electron/agent/llm/index.ts +6 -0
  125. package/src/electron/agent/llm/kimi-provider.ts +39 -0
  126. package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
  127. package/src/electron/agent/llm/openai-compatible.ts +133 -0
  128. package/src/electron/agent/llm/openai-oauth.ts +2 -1
  129. package/src/electron/agent/llm/openrouter-provider.ts +2 -1
  130. package/src/electron/agent/llm/provider-factory.ts +459 -6
  131. package/src/electron/agent/llm/types.ts +95 -1
  132. package/src/electron/agent/llm/xai-provider.ts +39 -0
  133. package/src/electron/agent/search/provider-factory.ts +43 -2
  134. package/src/electron/agent/tools/box-tools.ts +239 -0
  135. package/src/electron/agent/tools/builtin-settings.ts +36 -0
  136. package/src/electron/agent/tools/dropbox-tools.ts +237 -0
  137. package/src/electron/agent/tools/file-tools.ts +66 -3
  138. package/src/electron/agent/tools/gmail-tools.ts +240 -0
  139. package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
  140. package/src/electron/agent/tools/google-drive-tools.ts +228 -0
  141. package/src/electron/agent/tools/grep-tools.ts +97 -12
  142. package/src/electron/agent/tools/image-tools.ts +11 -1
  143. package/src/electron/agent/tools/notion-tools.ts +330 -0
  144. package/src/electron/agent/tools/onedrive-tools.ts +217 -0
  145. package/src/electron/agent/tools/registry.ts +794 -10
  146. package/src/electron/agent/tools/search-tools.ts +29 -11
  147. package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
  148. package/src/electron/agent/tools/shell-tools.ts +11 -3
  149. package/src/electron/agent/tools/x-tools.ts +1 -1
  150. package/src/electron/agents/agent-dispatch.ts +79 -0
  151. package/src/electron/database/SecureSettingsRepository.ts +7 -1
  152. package/src/electron/database/repositories.ts +58 -6
  153. package/src/electron/database/schema.ts +8 -0
  154. package/src/electron/gateway/channels/discord.ts +4 -0
  155. package/src/electron/gateway/channels/google-chat.ts +3 -0
  156. package/src/electron/gateway/channels/line.ts +3 -0
  157. package/src/electron/gateway/channels/matrix-client.ts +15 -0
  158. package/src/electron/gateway/channels/matrix.ts +31 -0
  159. package/src/electron/gateway/channels/mattermost.ts +3 -0
  160. package/src/electron/gateway/channels/signal.ts +3 -0
  161. package/src/electron/gateway/channels/slack.ts +9 -4
  162. package/src/electron/gateway/channels/teams.ts +4 -0
  163. package/src/electron/gateway/channels/telegram.ts +2 -0
  164. package/src/electron/gateway/channels/twitch.ts +2 -0
  165. package/src/electron/gateway/channels/types.ts +8 -0
  166. package/src/electron/gateway/channels/whatsapp.ts +66 -0
  167. package/src/electron/gateway/index.ts +95 -2
  168. package/src/electron/gateway/router.ts +231 -161
  169. package/src/electron/gateway/security.ts +21 -9
  170. package/src/electron/ipc/canvas-handlers.ts +10 -0
  171. package/src/electron/ipc/handlers.ts +848 -292
  172. package/src/electron/main.ts +35 -0
  173. package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
  174. package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
  175. package/src/electron/memory/MemoryService.ts +7 -1
  176. package/src/electron/preload.ts +200 -5
  177. package/src/electron/settings/appearance-manager.ts +20 -2
  178. package/src/electron/settings/box-manager.ts +58 -0
  179. package/src/electron/settings/dropbox-manager.ts +58 -0
  180. package/src/electron/settings/google-workspace-manager.ts +59 -0
  181. package/src/electron/settings/notion-manager.ts +60 -0
  182. package/src/electron/settings/onedrive-manager.ts +58 -0
  183. package/src/electron/settings/sharepoint-manager.ts +58 -0
  184. package/src/electron/utils/box-api.ts +184 -0
  185. package/src/electron/utils/dropbox-api.ts +171 -0
  186. package/src/electron/utils/env-migration.ts +22 -0
  187. package/src/electron/utils/gmail-api.ts +121 -0
  188. package/src/electron/utils/google-calendar-api.ts +115 -0
  189. package/src/electron/utils/google-workspace-api.ts +228 -0
  190. package/src/electron/utils/google-workspace-auth.ts +109 -0
  191. package/src/electron/utils/google-workspace-oauth.ts +232 -0
  192. package/src/electron/utils/notion-api.ts +126 -0
  193. package/src/electron/utils/onedrive-api.ts +137 -0
  194. package/src/electron/utils/sharepoint-api.ts +132 -0
  195. package/src/electron/utils/validation.ts +128 -1
  196. package/src/electron/utils/x-cli.ts +1 -1
  197. package/src/renderer/App.tsx +119 -8
  198. package/src/renderer/components/ActivityFeedItem.tsx +34 -17
  199. package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
  200. package/src/renderer/components/AppearanceSettings.tsx +37 -2
  201. package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
  202. package/src/renderer/components/BoxSettings.tsx +203 -0
  203. package/src/renderer/components/BrowserView.tsx +101 -0
  204. package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
  205. package/src/renderer/components/CanvasPreview.tsx +68 -1
  206. package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
  207. package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
  208. package/src/renderer/components/ConnectorsSettings.tsx +397 -0
  209. package/src/renderer/components/ControlPlaneSettings.tsx +2 -0
  210. package/src/renderer/components/DiscordSettings.tsx +18 -7
  211. package/src/renderer/components/DropboxSettings.tsx +202 -0
  212. package/src/renderer/components/EmailSettings.tsx +18 -7
  213. package/src/renderer/components/FileViewer.tsx +21 -13
  214. package/src/renderer/components/GoogleChatSettings.tsx +17 -7
  215. package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
  216. package/src/renderer/components/ImessageSettings.tsx +22 -11
  217. package/src/renderer/components/LineIcons.tsx +376 -0
  218. package/src/renderer/components/LineSettings.tsx +18 -7
  219. package/src/renderer/components/MCPSettings.tsx +56 -0
  220. package/src/renderer/components/MainContent.tsx +740 -76
  221. package/src/renderer/components/MatrixSettings.tsx +18 -7
  222. package/src/renderer/components/MattermostSettings.tsx +18 -7
  223. package/src/renderer/components/NodesSettings.tsx +58 -99
  224. package/src/renderer/components/NotificationPanel.tsx +25 -11
  225. package/src/renderer/components/NotionSettings.tsx +231 -0
  226. package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
  227. package/src/renderer/components/OnboardingModal.tsx +70 -1
  228. package/src/renderer/components/OneDriveSettings.tsx +212 -0
  229. package/src/renderer/components/RightPanel.tsx +141 -28
  230. package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
  231. package/src/renderer/components/SearchSettings.tsx +118 -114
  232. package/src/renderer/components/Settings.tsx +1425 -651
  233. package/src/renderer/components/SharePointSettings.tsx +224 -0
  234. package/src/renderer/components/Sidebar.tsx +94 -19
  235. package/src/renderer/components/SignalSettings.tsx +18 -7
  236. package/src/renderer/components/SkillHubBrowser.tsx +144 -185
  237. package/src/renderer/components/SlackSettings.tsx +18 -7
  238. package/src/renderer/components/TaskQuickActions.tsx +11 -6
  239. package/src/renderer/components/TaskTimeline.tsx +58 -26
  240. package/src/renderer/components/TeamsSettings.tsx +18 -7
  241. package/src/renderer/components/TelegramSettings.tsx +18 -7
  242. package/src/renderer/components/ThemeIcon.tsx +16 -0
  243. package/src/renderer/components/TwitchSettings.tsx +18 -7
  244. package/src/renderer/components/VoiceSettings.tsx +30 -74
  245. package/src/renderer/components/WhatsAppSettings.tsx +48 -37
  246. package/src/renderer/components/WorkingStateHistory.tsx +7 -5
  247. package/src/renderer/components/WorkspaceSelector.tsx +42 -13
  248. package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
  249. package/src/renderer/styles/index.css +2333 -209
  250. package/src/shared/channelMessages.ts +367 -4
  251. package/src/shared/llm-provider-catalog.ts +217 -0
  252. package/src/shared/types.ts +251 -2
@@ -0,0 +1,224 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { SharePointSettingsData } from '../../shared/types';
3
+
4
+ export function SharePointSettings() {
5
+ const [settings, setSettings] = useState<SharePointSettingsData | null>(null);
6
+ const [saving, setSaving] = useState(false);
7
+ const [testing, setTesting] = useState(false);
8
+ const [testResult, setTestResult] = useState<{ success: boolean; error?: string; name?: string; userId?: string } | null>(null);
9
+ const [status, setStatus] = useState<{ configured: boolean; connected: boolean; name?: string; error?: string } | null>(null);
10
+ const [statusLoading, setStatusLoading] = useState(false);
11
+
12
+ useEffect(() => {
13
+ loadSettings();
14
+ refreshStatus();
15
+ }, []);
16
+
17
+ const loadSettings = async () => {
18
+ try {
19
+ const loaded = await window.electronAPI.getSharePointSettings();
20
+ setSettings(loaded);
21
+ } catch (error) {
22
+ console.error('Failed to load SharePoint settings:', error);
23
+ }
24
+ };
25
+
26
+ const updateSettings = (updates: Partial<SharePointSettingsData>) => {
27
+ if (!settings) return;
28
+ setSettings({ ...settings, ...updates });
29
+ };
30
+
31
+ const handleSave = async () => {
32
+ if (!settings) return;
33
+ setSaving(true);
34
+ setTestResult(null);
35
+ try {
36
+ const payload: SharePointSettingsData = { ...settings };
37
+ await window.electronAPI.saveSharePointSettings(payload);
38
+ setSettings(payload);
39
+ await refreshStatus();
40
+ } catch (error) {
41
+ console.error('Failed to save SharePoint settings:', error);
42
+ } finally {
43
+ setSaving(false);
44
+ }
45
+ };
46
+
47
+ const refreshStatus = async () => {
48
+ try {
49
+ setStatusLoading(true);
50
+ const result = await window.electronAPI.getSharePointStatus();
51
+ setStatus(result);
52
+ } catch (error) {
53
+ console.error('Failed to load SharePoint status:', error);
54
+ } finally {
55
+ setStatusLoading(false);
56
+ }
57
+ };
58
+
59
+ const handleTestConnection = async () => {
60
+ setTesting(true);
61
+ setTestResult(null);
62
+ try {
63
+ const result = await window.electronAPI.testSharePointConnection();
64
+ setTestResult(result);
65
+ await refreshStatus();
66
+ } catch (error: any) {
67
+ setTestResult({ success: false, error: error.message || 'Failed to test connection' });
68
+ } finally {
69
+ setTesting(false);
70
+ }
71
+ };
72
+
73
+ if (!settings) {
74
+ return <div className="settings-loading">Loading SharePoint settings...</div>;
75
+ }
76
+
77
+ const statusLabel = !status?.configured
78
+ ? 'Missing Token'
79
+ : status.connected
80
+ ? 'Connected'
81
+ : 'Configured';
82
+
83
+ const statusClass = !status?.configured
84
+ ? 'missing'
85
+ : status.connected
86
+ ? 'connected'
87
+ : 'configured';
88
+
89
+ return (
90
+ <div className="sharepoint-settings">
91
+ <div className="settings-section">
92
+ <div className="settings-section-header">
93
+ <div className="settings-title-with-badge">
94
+ <h3>Connect SharePoint</h3>
95
+ {status && (
96
+ <span
97
+ className={`sharepoint-status-badge ${statusClass}`}
98
+ title={!status.configured ? 'Access token not configured' : status.connected ? 'Connected to SharePoint' : 'Configured'}
99
+ >
100
+ {statusLabel}
101
+ </span>
102
+ )}
103
+ {statusLoading && !status && (
104
+ <span className="sharepoint-status-badge configured">Checking…</span>
105
+ )}
106
+ </div>
107
+ <button className="btn-secondary btn-sm" onClick={refreshStatus} disabled={statusLoading}>
108
+ {statusLoading ? 'Checking...' : 'Refresh Status'}
109
+ </button>
110
+ </div>
111
+ <p className="settings-description">
112
+ Connect the agent to SharePoint using a Microsoft Graph access token, then use the built-in `sharepoint_action`
113
+ tool to search sites and manage drive items.
114
+ </p>
115
+ {status?.error && (
116
+ <p className="settings-hint">Status check: {status.error}</p>
117
+ )}
118
+ <div className="settings-actions">
119
+ <button
120
+ className="btn-secondary btn-sm"
121
+ onClick={() => window.electronAPI.openExternal('https://portal.azure.com')}
122
+ >
123
+ Open Azure Portal
124
+ </button>
125
+ </div>
126
+ </div>
127
+
128
+ <div className="settings-section">
129
+ <div className="settings-field">
130
+ <label>Enable Integration</label>
131
+ <label className="settings-toggle">
132
+ <input
133
+ type="checkbox"
134
+ checked={settings.enabled}
135
+ onChange={(e) => updateSettings({ enabled: e.target.checked })}
136
+ />
137
+ <span className="toggle-slider" />
138
+ </label>
139
+ </div>
140
+
141
+ <div className="settings-field">
142
+ <label>Access Token</label>
143
+ <input
144
+ type="password"
145
+ className="settings-input"
146
+ placeholder="Microsoft Graph access token"
147
+ value={settings.accessToken || ''}
148
+ onChange={(e) => updateSettings({ accessToken: e.target.value || undefined })}
149
+ />
150
+ <p className="settings-hint">Use a token with Sites.ReadWrite.All or Files.ReadWrite.All scope.</p>
151
+ </div>
152
+
153
+ <div className="settings-field">
154
+ <label>Site ID (optional)</label>
155
+ <input
156
+ type="text"
157
+ className="settings-input"
158
+ placeholder="SharePoint site ID"
159
+ value={settings.siteId || ''}
160
+ onChange={(e) => updateSettings({ siteId: e.target.value || undefined })}
161
+ />
162
+ </div>
163
+
164
+ <div className="settings-field">
165
+ <label>Drive ID (optional)</label>
166
+ <input
167
+ type="text"
168
+ className="settings-input"
169
+ placeholder="Default drive ID"
170
+ value={settings.driveId || ''}
171
+ onChange={(e) => updateSettings({ driveId: e.target.value || undefined })}
172
+ />
173
+ <p className="settings-hint">Set a default drive to simplify tool calls.</p>
174
+ </div>
175
+
176
+ <div className="settings-field">
177
+ <label>Timeout (ms)</label>
178
+ <input
179
+ type="number"
180
+ className="settings-input"
181
+ min={1000}
182
+ max={120000}
183
+ value={settings.timeoutMs ?? 20000}
184
+ onChange={(e) => updateSettings({ timeoutMs: Number(e.target.value) })}
185
+ />
186
+ </div>
187
+
188
+ <div className="settings-actions">
189
+ <button className="btn-secondary btn-sm" onClick={handleTestConnection} disabled={testing}>
190
+ {testing ? 'Testing...' : 'Test Connection'}
191
+ </button>
192
+ <button className="btn-primary btn-sm" onClick={handleSave} disabled={saving}>
193
+ {saving ? 'Saving...' : 'Save Settings'}
194
+ </button>
195
+ </div>
196
+
197
+ {testResult && (
198
+ <div className={`test-result ${testResult.success ? 'success' : 'error'}`}>
199
+ {testResult.success ? (
200
+ <span>Connected{testResult.name ? ` as ${testResult.name}` : ''}</span>
201
+ ) : (
202
+ <span>Connection failed: {testResult.error}</span>
203
+ )}
204
+ </div>
205
+ )}
206
+ </div>
207
+
208
+ <div className="settings-section">
209
+ <h4>Quick Usage</h4>
210
+ <pre className="settings-info-box">{`// Search sites
211
+ sharepoint_action({
212
+ action: "search_sites",
213
+ query: "Marketing"
214
+ });
215
+
216
+ // Upload a file to the default drive
217
+ sharepoint_action({
218
+ action: "upload_file",
219
+ file_path: "reports/summary.pdf"
220
+ });`}</pre>
221
+ </div>
222
+ </div>
223
+ );
224
+ }
@@ -7,6 +7,7 @@ interface SidebarProps {
7
7
  selectedTaskId: string | null;
8
8
  onSelectTask: (id: string | null) => void;
9
9
  onOpenSettings: () => void;
10
+ onOpenMissionControl: () => void;
10
11
  onTasksChanged: () => void;
11
12
  }
12
13
 
@@ -22,6 +23,7 @@ export function Sidebar({
22
23
  selectedTaskId,
23
24
  onSelectTask,
24
25
  onOpenSettings,
26
+ onOpenMissionControl,
25
27
  onTasksChanged,
26
28
  }: SidebarProps) {
27
29
  const [menuOpenTaskId, setMenuOpenTaskId] = useState<string | null>(null);
@@ -140,19 +142,61 @@ export function Sidebar({
140
142
  const getStatusIndicator = (status: Task['status']) => {
141
143
  switch (status) {
142
144
  case 'completed':
143
- return '[✓]';
145
+ return (
146
+ <>
147
+ <span className="terminal-only">[✓]</span>
148
+ <span className="modern-only">
149
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
150
+ </span>
151
+ </>
152
+ );
144
153
  case 'paused':
145
- return '[P]';
154
+ return (
155
+ <>
156
+ <span className="terminal-only">[P]</span>
157
+ <span className="modern-only">
158
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="10" y1="15" x2="10" y2="9"></line><line x1="14" y1="15" x2="14" y2="9"></line></svg>
159
+ </span>
160
+ </>
161
+ );
146
162
  case 'blocked':
147
- return '[!]';
163
+ return (
164
+ <>
165
+ <span className="terminal-only">[!]</span>
166
+ <span className="modern-only">
167
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
168
+ </span>
169
+ </>
170
+ );
148
171
  case 'failed':
149
172
  case 'cancelled':
150
- return '[✗]';
173
+ return (
174
+ <>
175
+ <span className="terminal-only">[✗]</span>
176
+ <span className="modern-only">
177
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
178
+ </span>
179
+ </>
180
+ );
151
181
  case 'executing':
152
182
  case 'planning':
153
- return '[~]';
183
+ return (
184
+ <>
185
+ <span className="terminal-only">[~]</span>
186
+ <span className="modern-only">
187
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle></svg>
188
+ </span>
189
+ </>
190
+ );
154
191
  default:
155
- return '[ ]';
192
+ return (
193
+ <>
194
+ <span className="terminal-only">[ ]</span>
195
+ <span className="modern-only">
196
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" opacity="0.3"></circle></svg>
197
+ </span>
198
+ </>
199
+ );
156
200
  }
157
201
  };
158
202
 
@@ -302,25 +346,51 @@ export function Sidebar({
302
346
  <div className="sidebar cli-sidebar">
303
347
  {/* New Session Button */}
304
348
  <div className="sidebar-header">
305
- <button className="new-task-btn cli-new-task-btn" onClick={handleNewTask}>
306
- <span className="cli-btn-bracket">[</span>
307
- <span className="cli-btn-plus">+</span>
308
- <span className="cli-btn-bracket">]</span>
309
- <span className="cli-btn-text">new_session</span>
310
- </button>
349
+ <div className="cli-header-actions">
350
+ <button
351
+ className="cli-action-btn cli-mission-control-btn"
352
+ onClick={onOpenMissionControl}
353
+ title="Mission Control"
354
+ >
355
+ <span className="terminal-only">
356
+ <span className="cli-btn-bracket">[</span>
357
+ <span className="cli-btn-accent">MC</span>
358
+ <span className="cli-btn-bracket">]</span>
359
+ </span>
360
+ <span className="cli-btn-text">
361
+ <span className="terminal-only">mission_control</span>
362
+ <span className="modern-only">Mission Control</span>
363
+ </span>
364
+ </button>
365
+ <button className="new-task-btn cli-new-task-btn cli-action-btn" onClick={handleNewTask}>
366
+ <span className="terminal-only">
367
+ <span className="cli-btn-bracket">[</span>
368
+ <span className="cli-btn-plus">+</span>
369
+ <span className="cli-btn-bracket">]</span>
370
+ </span>
371
+ <span className="cli-btn-text">
372
+ <span className="terminal-only">new_session</span>
373
+ <span className="modern-only">New Session</span>
374
+ </span>
375
+ </button>
376
+ </div>
311
377
  </div>
312
378
 
313
379
  {/* Sessions List */}
314
380
  <div className="task-list cli-task-list">
315
381
  <div className="task-list-header cli-list-header">
316
382
  <span className="cli-section-prompt">&gt;</span>
317
- <span>SESSIONS</span>
383
+ <span className="terminal-only">SESSIONS</span>
384
+ <span className="modern-only">Sessions</span>
318
385
  </div>
319
386
  {taskTree.length === 0 ? (
320
387
  <div className="sidebar-empty cli-empty">
321
- <pre className="cli-tree">{`├── (no sessions yet)
388
+ <pre className="cli-tree terminal-only">{`├── (no sessions yet)
322
389
  └── ...`}</pre>
323
- <p className="cli-hint"># start a new session above</p>
390
+ <p className="cli-hint">
391
+ <span className="terminal-only"># start a new session above</span>
392
+ <span className="modern-only">Start a new session to begin</span>
393
+ </p>
324
394
  </div>
325
395
  ) : (
326
396
  taskTree.map((node, index) =>
@@ -332,12 +402,17 @@ export function Sidebar({
332
402
  {/* Footer */}
333
403
  <div className="sidebar-footer cli-sidebar-footer">
334
404
  <div className="cli-footer-info">
335
- <span className="cli-footer-label">SYS:</span>
405
+ <span className="cli-footer-label">
406
+ <span className="terminal-only">SYS:</span>
407
+ </span>
336
408
  <span className="cli-footer-value">CoWork OS</span>
337
409
  </div>
338
- <button className="settings-btn cli-settings-btn" onClick={onOpenSettings} title="Settings">
339
- [cfg]
340
- </button>
410
+ <div className="cli-footer-actions">
411
+ <button className="settings-btn cli-settings-btn" onClick={onOpenSettings} title="Settings">
412
+ <span className="terminal-only">[cfg]</span>
413
+ <span className="modern-only">Settings</span>
414
+ </button>
415
+ </div>
341
416
  </div>
342
417
  </div>
343
418
  );
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from 'react';
1
+ import { useState, useEffect, useCallback } from 'react';
2
2
  import { ChannelData, ChannelUserData, SecurityMode } from '../../shared/types';
3
3
 
4
4
  interface SignalSettingsProps {
@@ -35,11 +35,7 @@ export function SignalSettings({ onStatusChange }: SignalSettingsProps) {
35
35
  // Pairing code state
36
36
  const [pairingCode, setPairingCode] = useState<string | null>(null);
37
37
 
38
- useEffect(() => {
39
- loadChannel();
40
- }, []);
41
-
42
- const loadChannel = async () => {
38
+ const loadChannel = useCallback(async () => {
43
39
  try {
44
40
  setLoading(true);
45
41
  const channels = await window.electronAPI.getGatewayChannels();
@@ -75,7 +71,22 @@ export function SignalSettings({ onStatusChange }: SignalSettingsProps) {
75
71
  } finally {
76
72
  setLoading(false);
77
73
  }
78
- };
74
+ }, [onStatusChange]);
75
+
76
+ useEffect(() => {
77
+ loadChannel();
78
+ }, [loadChannel]);
79
+
80
+ useEffect(() => {
81
+ const unsubscribe = window.electronAPI?.onGatewayUsersUpdated?.((data) => {
82
+ if (data?.channelType !== 'signal') return;
83
+ if (channel && data?.channelId && data.channelId !== channel.id) return;
84
+ loadChannel();
85
+ });
86
+ return () => {
87
+ if (unsubscribe) unsubscribe();
88
+ };
89
+ }, [channel?.id, loadChannel]);
79
90
 
80
91
  const handleAddChannel = async () => {
81
92
  if (!phoneNumber.trim()) {