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,126 @@
1
+ /**
2
+ * Notion API helpers
3
+ */
4
+
5
+ import { NotionConnectionTestResult, NotionSettingsData } from '../../shared/types';
6
+
7
+ export const NOTION_API_BASE = 'https://api.notion.com/v1';
8
+ export const DEFAULT_NOTION_VERSION = '2025-09-03';
9
+ const DEFAULT_TIMEOUT_MS = 20000;
10
+
11
+ function getNotionVersion(settings: NotionSettingsData): string {
12
+ return settings.notionVersion || DEFAULT_NOTION_VERSION;
13
+ }
14
+
15
+ function parseJsonSafe(text: string): any | undefined {
16
+ const trimmed = text.trim();
17
+ if (!trimmed) return undefined;
18
+ try {
19
+ return JSON.parse(trimmed);
20
+ } catch {
21
+ return undefined;
22
+ }
23
+ }
24
+
25
+ function formatNotionError(status: number, data: any, fallback?: string): string {
26
+ const message =
27
+ data?.message ||
28
+ data?.error ||
29
+ data?.details ||
30
+ fallback ||
31
+ 'Notion API error';
32
+ return `Notion API error ${status}: ${message}`;
33
+ }
34
+
35
+ export interface NotionRequestOptions {
36
+ method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
37
+ path: string;
38
+ body?: Record<string, any>;
39
+ timeoutMs?: number;
40
+ }
41
+
42
+ export interface NotionRequestResult {
43
+ status: number;
44
+ data?: any;
45
+ raw?: string;
46
+ }
47
+
48
+ export async function notionRequest(
49
+ settings: NotionSettingsData,
50
+ options: NotionRequestOptions
51
+ ): Promise<NotionRequestResult> {
52
+ if (!settings.apiKey) {
53
+ throw new Error('Notion API key not configured. Add it in Settings > Integrations > Notion.');
54
+ }
55
+
56
+ const url = `${NOTION_API_BASE}${options.path}`;
57
+ const headers: Record<string, string> = {
58
+ Authorization: `Bearer ${settings.apiKey}`,
59
+ 'Notion-Version': getNotionVersion(settings),
60
+ };
61
+
62
+ if (options.method !== 'GET' && options.method !== 'DELETE') {
63
+ headers['Content-Type'] = 'application/json';
64
+ }
65
+
66
+ const timeoutMs = options.timeoutMs ?? settings.timeoutMs ?? DEFAULT_TIMEOUT_MS;
67
+ const controller = new AbortController();
68
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
69
+
70
+ try {
71
+ const response = await fetch(url, {
72
+ method: options.method,
73
+ headers,
74
+ body: options.body ? JSON.stringify(options.body) : undefined,
75
+ signal: controller.signal,
76
+ });
77
+
78
+ const rawText = typeof response.text === 'function' ? await response.text() : '';
79
+ const data = rawText ? parseJsonSafe(rawText) : undefined;
80
+
81
+ if (!response.ok) {
82
+ throw new Error(formatNotionError(response.status, data, response.statusText));
83
+ }
84
+
85
+ return {
86
+ status: response.status,
87
+ data: data ?? undefined,
88
+ raw: rawText || undefined,
89
+ };
90
+ } catch (error: any) {
91
+ if (error?.name === 'AbortError') {
92
+ throw new Error('Notion API request timed out');
93
+ }
94
+ throw error;
95
+ } finally {
96
+ clearTimeout(timeout);
97
+ }
98
+ }
99
+
100
+ function extractUserInfo(data: any): { name?: string; userId?: string } {
101
+ if (!data || typeof data !== 'object') return {};
102
+ const name =
103
+ data.name ||
104
+ data?.bot?.owner?.user?.name ||
105
+ data?.person?.name ||
106
+ undefined;
107
+ const userId = data.id || data.user_id || undefined;
108
+ return { name, userId };
109
+ }
110
+
111
+ export async function testNotionConnection(settings: NotionSettingsData): Promise<NotionConnectionTestResult> {
112
+ try {
113
+ const result = await notionRequest(settings, { method: 'GET', path: '/users/me' });
114
+ const extracted = extractUserInfo(result.data);
115
+ return {
116
+ success: true,
117
+ name: extracted.name,
118
+ userId: extracted.userId,
119
+ };
120
+ } catch (error: any) {
121
+ return {
122
+ success: false,
123
+ error: error?.message || 'Failed to connect to Notion',
124
+ };
125
+ }
126
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * OneDrive API helpers (Microsoft Graph)
3
+ */
4
+
5
+ import { OneDriveConnectionTestResult, OneDriveSettingsData } from '../../shared/types';
6
+
7
+ export const ONEDRIVE_API_BASE = 'https://graph.microsoft.com/v1.0';
8
+ const DEFAULT_TIMEOUT_MS = 20000;
9
+
10
+ function parseJsonSafe(text: string): any | undefined {
11
+ const trimmed = text.trim();
12
+ if (!trimmed) return undefined;
13
+ try {
14
+ return JSON.parse(trimmed);
15
+ } catch {
16
+ return undefined;
17
+ }
18
+ }
19
+
20
+ function formatGraphError(status: number, data: any, fallback?: string): string {
21
+ const message =
22
+ data?.error?.message ||
23
+ data?.message ||
24
+ fallback ||
25
+ 'Microsoft Graph error';
26
+ return `Microsoft Graph error ${status}: ${message}`;
27
+ }
28
+
29
+ export interface OneDriveRequestOptions {
30
+ method: 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT';
31
+ path: string;
32
+ query?: Record<string, string | number | boolean | undefined>;
33
+ body?: any;
34
+ headers?: Record<string, string>;
35
+ timeoutMs?: number;
36
+ }
37
+
38
+ export interface OneDriveRequestResult {
39
+ status: number;
40
+ data?: any;
41
+ raw?: string;
42
+ }
43
+
44
+ export async function onedriveRequest(
45
+ settings: OneDriveSettingsData,
46
+ options: OneDriveRequestOptions
47
+ ): Promise<OneDriveRequestResult> {
48
+ if (!settings.accessToken) {
49
+ throw new Error('OneDrive access token not configured. Add it in Settings > Integrations > OneDrive.');
50
+ }
51
+
52
+ const params = new URLSearchParams();
53
+ if (options.query) {
54
+ for (const [key, value] of Object.entries(options.query)) {
55
+ if (value === undefined || value === null) continue;
56
+ params.set(key, String(value));
57
+ }
58
+ }
59
+ const queryString = params.toString();
60
+ const url = `${ONEDRIVE_API_BASE}${options.path}${queryString ? `?${queryString}` : ''}`;
61
+
62
+ const headers: Record<string, string> = {
63
+ Authorization: `Bearer ${settings.accessToken}`,
64
+ ...(options.headers || {}),
65
+ };
66
+
67
+ const isBinaryBody = options.body instanceof Uint8Array || options.body instanceof ArrayBuffer || Buffer.isBuffer(options.body);
68
+ if (options.body && !isBinaryBody && options.method !== 'GET' && options.method !== 'DELETE') {
69
+ headers['Content-Type'] = headers['Content-Type'] || 'application/json';
70
+ }
71
+
72
+ const timeoutMs = options.timeoutMs ?? settings.timeoutMs ?? DEFAULT_TIMEOUT_MS;
73
+ const controller = new AbortController();
74
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
75
+
76
+ try {
77
+ const response = await fetch(url, {
78
+ method: options.method,
79
+ headers,
80
+ body: options.body
81
+ ? isBinaryBody
82
+ ? options.body
83
+ : JSON.stringify(options.body)
84
+ : undefined,
85
+ signal: controller.signal,
86
+ });
87
+
88
+ const rawText = typeof response.text === 'function' ? await response.text() : '';
89
+ const data = rawText ? parseJsonSafe(rawText) : undefined;
90
+
91
+ if (!response.ok) {
92
+ throw new Error(formatGraphError(response.status, data, response.statusText));
93
+ }
94
+
95
+ return {
96
+ status: response.status,
97
+ data: data ?? undefined,
98
+ raw: rawText || undefined,
99
+ };
100
+ } catch (error: any) {
101
+ if (error?.name === 'AbortError') {
102
+ throw new Error('OneDrive API request timed out');
103
+ }
104
+ throw error;
105
+ } finally {
106
+ clearTimeout(timeout);
107
+ }
108
+ }
109
+
110
+ function extractDriveOwner(data: any): { name?: string; userId?: string; driveId?: string } {
111
+ if (!data || typeof data !== 'object') return {};
112
+ const name =
113
+ data?.owner?.user?.displayName ||
114
+ data?.owner?.user?.id ||
115
+ undefined;
116
+ const userId = data?.owner?.user?.id || undefined;
117
+ const driveId = data?.id || undefined;
118
+ return { name, userId, driveId };
119
+ }
120
+
121
+ export async function testOneDriveConnection(settings: OneDriveSettingsData): Promise<OneDriveConnectionTestResult> {
122
+ try {
123
+ const result = await onedriveRequest(settings, { method: 'GET', path: '/me/drive' });
124
+ const extracted = extractDriveOwner(result.data);
125
+ return {
126
+ success: true,
127
+ name: extracted.name,
128
+ userId: extracted.userId,
129
+ driveId: extracted.driveId,
130
+ };
131
+ } catch (error: any) {
132
+ return {
133
+ success: false,
134
+ error: error?.message || 'Failed to connect to OneDrive',
135
+ };
136
+ }
137
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * SharePoint API helpers (Microsoft Graph)
3
+ */
4
+
5
+ import { SharePointConnectionTestResult, SharePointSettingsData } from '../../shared/types';
6
+
7
+ export const SHAREPOINT_API_BASE = 'https://graph.microsoft.com/v1.0';
8
+ const DEFAULT_TIMEOUT_MS = 20000;
9
+
10
+ function parseJsonSafe(text: string): any | undefined {
11
+ const trimmed = text.trim();
12
+ if (!trimmed) return undefined;
13
+ try {
14
+ return JSON.parse(trimmed);
15
+ } catch {
16
+ return undefined;
17
+ }
18
+ }
19
+
20
+ function formatGraphError(status: number, data: any, fallback?: string): string {
21
+ const message =
22
+ data?.error?.message ||
23
+ data?.message ||
24
+ fallback ||
25
+ 'Microsoft Graph error';
26
+ return `Microsoft Graph error ${status}: ${message}`;
27
+ }
28
+
29
+ export interface SharePointRequestOptions {
30
+ method: 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT';
31
+ path: string;
32
+ query?: Record<string, string | number | boolean | undefined>;
33
+ body?: any;
34
+ headers?: Record<string, string>;
35
+ timeoutMs?: number;
36
+ }
37
+
38
+ export interface SharePointRequestResult {
39
+ status: number;
40
+ data?: any;
41
+ raw?: string;
42
+ }
43
+
44
+ export async function sharepointRequest(
45
+ settings: SharePointSettingsData,
46
+ options: SharePointRequestOptions
47
+ ): Promise<SharePointRequestResult> {
48
+ if (!settings.accessToken) {
49
+ throw new Error('SharePoint access token not configured. Add it in Settings > Integrations > SharePoint.');
50
+ }
51
+
52
+ const params = new URLSearchParams();
53
+ if (options.query) {
54
+ for (const [key, value] of Object.entries(options.query)) {
55
+ if (value === undefined || value === null) continue;
56
+ params.set(key, String(value));
57
+ }
58
+ }
59
+ const queryString = params.toString();
60
+ const url = `${SHAREPOINT_API_BASE}${options.path}${queryString ? `?${queryString}` : ''}`;
61
+
62
+ const headers: Record<string, string> = {
63
+ Authorization: `Bearer ${settings.accessToken}`,
64
+ ...(options.headers || {}),
65
+ };
66
+
67
+ const isBinaryBody = options.body instanceof Uint8Array || options.body instanceof ArrayBuffer || Buffer.isBuffer(options.body);
68
+ if (options.body && !isBinaryBody && options.method !== 'GET' && options.method !== 'DELETE') {
69
+ headers['Content-Type'] = headers['Content-Type'] || 'application/json';
70
+ }
71
+
72
+ const timeoutMs = options.timeoutMs ?? settings.timeoutMs ?? DEFAULT_TIMEOUT_MS;
73
+ const controller = new AbortController();
74
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
75
+
76
+ try {
77
+ const response = await fetch(url, {
78
+ method: options.method,
79
+ headers,
80
+ body: options.body
81
+ ? isBinaryBody
82
+ ? options.body
83
+ : JSON.stringify(options.body)
84
+ : undefined,
85
+ signal: controller.signal,
86
+ });
87
+
88
+ const rawText = typeof response.text === 'function' ? await response.text() : '';
89
+ const data = rawText ? parseJsonSafe(rawText) : undefined;
90
+
91
+ if (!response.ok) {
92
+ throw new Error(formatGraphError(response.status, data, response.statusText));
93
+ }
94
+
95
+ return {
96
+ status: response.status,
97
+ data: data ?? undefined,
98
+ raw: rawText || undefined,
99
+ };
100
+ } catch (error: any) {
101
+ if (error?.name === 'AbortError') {
102
+ throw new Error('SharePoint API request timed out');
103
+ }
104
+ throw error;
105
+ } finally {
106
+ clearTimeout(timeout);
107
+ }
108
+ }
109
+
110
+ function extractUserInfo(data: any): { name?: string; userId?: string } {
111
+ if (!data || typeof data !== 'object') return {};
112
+ const name = data.displayName || data.name || undefined;
113
+ const userId = data.id || undefined;
114
+ return { name, userId };
115
+ }
116
+
117
+ export async function testSharePointConnection(settings: SharePointSettingsData): Promise<SharePointConnectionTestResult> {
118
+ try {
119
+ const result = await sharepointRequest(settings, { method: 'GET', path: '/me' });
120
+ const extracted = extractUserInfo(result.data);
121
+ return {
122
+ success: true,
123
+ name: extracted.name,
124
+ userId: extracted.userId,
125
+ };
126
+ } catch (error: any) {
127
+ return {
128
+ success: false,
129
+ error: error?.message || 'Failed to connect to SharePoint',
130
+ };
131
+ }
132
+ }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { z } from 'zod';
7
+ import { LLM_PROVIDER_TYPES } from '../../shared/types';
7
8
 
8
9
  // Common validation patterns
9
10
  const MAX_STRING_LENGTH = 10000;
@@ -63,6 +64,26 @@ export const TaskMessageSchema = z.object({
63
64
  message: z.string().min(1).max(MAX_PROMPT_LENGTH),
64
65
  });
65
66
 
67
+ export const FileImportSchema = z.object({
68
+ workspaceId: z.string().refine(
69
+ (val) => val === TEMP_WORKSPACE_ID || z.string().uuid().safeParse(val).success,
70
+ { message: 'Must be a valid UUID or temp workspace ID' }
71
+ ),
72
+ files: z.array(z.string().min(1).max(MAX_PATH_LENGTH)).min(1).max(20),
73
+ });
74
+
75
+ export const FileImportDataSchema = z.object({
76
+ workspaceId: z.string().refine(
77
+ (val) => val === TEMP_WORKSPACE_ID || z.string().uuid().safeParse(val).success,
78
+ { message: 'Must be a valid UUID or temp workspace ID' }
79
+ ),
80
+ files: z.array(z.object({
81
+ name: z.string().min(1).max(MAX_PATH_LENGTH),
82
+ data: z.string().min(1),
83
+ mimeType: z.string().max(200).optional(),
84
+ })).min(1).max(20),
85
+ });
86
+
66
87
  // ============ Approval Schemas ============
67
88
 
68
89
  export const ApprovalResponseSchema = z.object({
@@ -72,7 +93,7 @@ export const ApprovalResponseSchema = z.object({
72
93
 
73
94
  // ============ LLM Settings Schemas ============
74
95
 
75
- export const LLMProviderTypeSchema = z.enum(['anthropic', 'bedrock', 'ollama', 'gemini', 'openrouter', 'openai']);
96
+ export const LLMProviderTypeSchema = z.enum(LLM_PROVIDER_TYPES);
76
97
 
77
98
  export const AnthropicSettingsSchema = z.object({
78
99
  apiKey: z.string().max(500).optional(),
@@ -102,6 +123,7 @@ export const GeminiSettingsSchema = z.object({
102
123
  export const OpenRouterSettingsSchema = z.object({
103
124
  apiKey: z.string().max(500).optional(),
104
125
  model: z.string().max(200).optional(),
126
+ baseUrl: z.string().max(500).optional(),
105
127
  }).optional();
106
128
 
107
129
  export const OpenAISettingsSchema = z.object({
@@ -114,6 +136,40 @@ export const OpenAISettingsSchema = z.object({
114
136
  authMethod: z.enum(['api_key', 'oauth']).optional(),
115
137
  }).optional();
116
138
 
139
+ export const AzureSettingsSchema = z.object({
140
+ apiKey: z.string().max(500).optional(),
141
+ endpoint: z.string().max(500).optional(),
142
+ deployment: z.string().max(200).optional(),
143
+ deployments: z.array(z.string().max(200)).max(50).optional(),
144
+ apiVersion: z.string().max(200).optional(),
145
+ }).optional();
146
+
147
+ export const GroqSettingsSchema = z.object({
148
+ apiKey: z.string().max(500).optional(),
149
+ model: z.string().max(200).optional(),
150
+ baseUrl: z.string().max(500).optional(),
151
+ }).optional();
152
+
153
+ export const XAISettingsSchema = z.object({
154
+ apiKey: z.string().max(500).optional(),
155
+ model: z.string().max(200).optional(),
156
+ baseUrl: z.string().max(500).optional(),
157
+ }).optional();
158
+
159
+ export const KimiSettingsSchema = z.object({
160
+ apiKey: z.string().max(500).optional(),
161
+ model: z.string().max(200).optional(),
162
+ baseUrl: z.string().max(500).optional(),
163
+ }).optional();
164
+
165
+ export const CustomProviderConfigSchema = z.object({
166
+ apiKey: z.string().max(500).optional(),
167
+ model: z.string().max(200).optional(),
168
+ baseUrl: z.string().max(500).optional(),
169
+ });
170
+
171
+ export const CustomProvidersSchema = z.record(z.string(), CustomProviderConfigSchema).optional();
172
+
117
173
  export const LLMSettingsSchema = z.object({
118
174
  providerType: LLMProviderTypeSchema,
119
175
  modelKey: z.string().max(200),
@@ -123,6 +179,11 @@ export const LLMSettingsSchema = z.object({
123
179
  gemini: GeminiSettingsSchema,
124
180
  openrouter: OpenRouterSettingsSchema,
125
181
  openai: OpenAISettingsSchema,
182
+ azure: AzureSettingsSchema,
183
+ groq: GroqSettingsSchema,
184
+ xai: XAISettingsSchema,
185
+ kimi: KimiSettingsSchema,
186
+ customProviders: CustomProvidersSchema,
126
187
  });
127
188
 
128
189
  // ============ Search Settings Schemas ============
@@ -163,6 +224,63 @@ export const XSettingsSchema = z.object({
163
224
  quoteDepth: z.number().int().min(0).max(5).optional(),
164
225
  });
165
226
 
227
+ // ============ Notion Settings Schema ============
228
+
229
+ export const NotionSettingsSchema = z.object({
230
+ enabled: z.boolean().default(false),
231
+ apiKey: z.string().max(2000).optional(),
232
+ notionVersion: z.string().max(50).optional(),
233
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
234
+ });
235
+
236
+ // ============ Box Settings Schema ============
237
+
238
+ export const BoxSettingsSchema = z.object({
239
+ enabled: z.boolean().default(false),
240
+ accessToken: z.string().max(4000).optional(),
241
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
242
+ });
243
+
244
+ // ============ OneDrive Settings Schema ============
245
+
246
+ export const OneDriveSettingsSchema = z.object({
247
+ enabled: z.boolean().default(false),
248
+ accessToken: z.string().max(4000).optional(),
249
+ driveId: z.string().max(200).optional(),
250
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
251
+ });
252
+
253
+ // ============ Google Workspace Settings Schema ============
254
+
255
+ export const GoogleWorkspaceSettingsSchema = z.object({
256
+ enabled: z.boolean().default(false),
257
+ clientId: z.string().max(4000).optional(),
258
+ clientSecret: z.string().max(4000).optional(),
259
+ accessToken: z.string().max(4000).optional(),
260
+ refreshToken: z.string().max(4000).optional(),
261
+ tokenExpiresAt: z.number().int().optional(),
262
+ scopes: z.array(z.string().max(200)).optional(),
263
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
264
+ });
265
+
266
+ // ============ Dropbox Settings Schema ============
267
+
268
+ export const DropboxSettingsSchema = z.object({
269
+ enabled: z.boolean().default(false),
270
+ accessToken: z.string().max(4000).optional(),
271
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
272
+ });
273
+
274
+ // ============ SharePoint Settings Schema ============
275
+
276
+ export const SharePointSettingsSchema = z.object({
277
+ enabled: z.boolean().default(false),
278
+ accessToken: z.string().max(4000).optional(),
279
+ siteId: z.string().max(500).optional(),
280
+ driveId: z.string().max(500).optional(),
281
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
282
+ });
283
+
166
284
  // ============ Guardrail Settings Schema ============
167
285
 
168
286
  export const GuardrailSettingsSchema = z.object({
@@ -451,6 +569,15 @@ export const MCPRegistrySearchSchema = z.object({
451
569
  offset: z.number().int().min(0).default(0),
452
570
  });
453
571
 
572
+ export const MCPConnectorOAuthSchema = z.object({
573
+ provider: z.enum(['salesforce', 'jira', 'hubspot', 'zendesk']),
574
+ clientId: z.string().min(1).max(500),
575
+ clientSecret: z.string().max(500).optional(),
576
+ scopes: z.array(z.string().max(200)).max(50).optional(),
577
+ loginUrl: z.string().url().max(500).optional(),
578
+ subdomain: z.string().max(200).optional(),
579
+ });
580
+
454
581
  // ============ Hooks (Webhooks) Schemas ============
455
582
 
456
583
  export const HookMappingChannelSchema = z.enum(['telegram', 'discord', 'slack', 'whatsapp', 'imessage', 'signal', 'mattermost', 'matrix', 'twitch', 'line', 'bluebubbles', 'email', 'last']);
@@ -46,7 +46,7 @@ function buildGlobalArgs(settings: XSettingsData, json: boolean): string[] {
46
46
 
47
47
  if (settings.authMethod === 'manual') {
48
48
  if (!settings.authToken || !settings.ct0) {
49
- throw new Error('Missing auth_token or ct0. Add them in Settings > More Channels > X.');
49
+ throw new Error('Missing auth_token or ct0. Add them in Settings > X (Twitter).');
50
50
  }
51
51
  args.push('--auth-token', settings.authToken, '--ct0', settings.ct0);
52
52
  } else {