cowork-os 0.3.21 → 0.3.23

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 (170) hide show
  1. package/README.md +293 -6
  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/daemon.js +25 -0
  48. package/dist/electron/electron/agent/executor.js +181 -26
  49. package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
  50. package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
  51. package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
  52. package/dist/electron/electron/agent/llm/index.js +11 -1
  53. package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
  54. package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
  55. package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
  56. package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
  57. package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
  58. package/dist/electron/electron/agent/llm/provider-factory.js +318 -4
  59. package/dist/electron/electron/agent/llm/types.js +66 -1
  60. package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
  61. package/dist/electron/electron/agent/tools/box-tools.js +231 -0
  62. package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
  63. package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
  64. package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
  65. package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
  66. package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
  67. package/dist/electron/electron/agent/tools/registry.js +541 -0
  68. package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
  69. package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
  70. package/dist/electron/electron/agent/tools/x-tools.js +1 -1
  71. package/dist/electron/electron/gateway/index.js +1 -0
  72. package/dist/electron/electron/gateway/router.js +123 -143
  73. package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
  74. package/dist/electron/electron/ipc/handlers.js +627 -158
  75. package/dist/electron/electron/main.js +63 -0
  76. package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
  77. package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
  78. package/dist/electron/electron/memory/MemoryService.js +1 -1
  79. package/dist/electron/electron/preload.js +74 -1
  80. package/dist/electron/electron/settings/box-manager.js +54 -0
  81. package/dist/electron/electron/settings/dropbox-manager.js +54 -0
  82. package/dist/electron/electron/settings/google-drive-manager.js +54 -0
  83. package/dist/electron/electron/settings/notion-manager.js +56 -0
  84. package/dist/electron/electron/settings/onedrive-manager.js +54 -0
  85. package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
  86. package/dist/electron/electron/utils/box-api.js +153 -0
  87. package/dist/electron/electron/utils/dropbox-api.js +144 -0
  88. package/dist/electron/electron/utils/env-migration.js +19 -0
  89. package/dist/electron/electron/utils/google-drive-api.js +152 -0
  90. package/dist/electron/electron/utils/notion-api.js +103 -0
  91. package/dist/electron/electron/utils/onedrive-api.js +113 -0
  92. package/dist/electron/electron/utils/sharepoint-api.js +109 -0
  93. package/dist/electron/electron/utils/validation.js +82 -3
  94. package/dist/electron/electron/utils/x-cli.js +1 -1
  95. package/dist/electron/shared/channelMessages.js +284 -3
  96. package/dist/electron/shared/llm-provider-catalog.js +198 -0
  97. package/dist/electron/shared/types.js +88 -1
  98. package/package.json +12 -2
  99. package/src/electron/agent/executor.ts +205 -28
  100. package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
  101. package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
  102. package/src/electron/agent/llm/groq-provider.ts +39 -0
  103. package/src/electron/agent/llm/index.ts +5 -0
  104. package/src/electron/agent/llm/kimi-provider.ts +39 -0
  105. package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
  106. package/src/electron/agent/llm/openai-compatible.ts +133 -0
  107. package/src/electron/agent/llm/openai-oauth.ts +2 -1
  108. package/src/electron/agent/llm/openrouter-provider.ts +2 -1
  109. package/src/electron/agent/llm/provider-factory.ts +414 -6
  110. package/src/electron/agent/llm/types.ts +90 -1
  111. package/src/electron/agent/llm/xai-provider.ts +39 -0
  112. package/src/electron/agent/tools/box-tools.ts +239 -0
  113. package/src/electron/agent/tools/builtin-settings.ts +34 -0
  114. package/src/electron/agent/tools/dropbox-tools.ts +237 -0
  115. package/src/electron/agent/tools/google-drive-tools.ts +228 -0
  116. package/src/electron/agent/tools/notion-tools.ts +330 -0
  117. package/src/electron/agent/tools/onedrive-tools.ts +217 -0
  118. package/src/electron/agent/tools/registry.ts +565 -0
  119. package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
  120. package/src/electron/agent/tools/shell-tools.ts +11 -3
  121. package/src/electron/agent/tools/x-tools.ts +1 -1
  122. package/src/electron/database/SecureSettingsRepository.ts +7 -1
  123. package/src/electron/gateway/index.ts +1 -0
  124. package/src/electron/gateway/router.ts +134 -149
  125. package/src/electron/ipc/canvas-handlers.ts +10 -0
  126. package/src/electron/ipc/handlers.ts +673 -153
  127. package/src/electron/main.ts +35 -0
  128. package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
  129. package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
  130. package/src/electron/memory/MemoryService.ts +5 -1
  131. package/src/electron/preload.ts +167 -4
  132. package/src/electron/settings/box-manager.ts +58 -0
  133. package/src/electron/settings/dropbox-manager.ts +58 -0
  134. package/src/electron/settings/google-drive-manager.ts +58 -0
  135. package/src/electron/settings/notion-manager.ts +60 -0
  136. package/src/electron/settings/onedrive-manager.ts +58 -0
  137. package/src/electron/settings/sharepoint-manager.ts +58 -0
  138. package/src/electron/utils/box-api.ts +184 -0
  139. package/src/electron/utils/dropbox-api.ts +171 -0
  140. package/src/electron/utils/env-migration.ts +22 -0
  141. package/src/electron/utils/google-drive-api.ts +183 -0
  142. package/src/electron/utils/notion-api.ts +126 -0
  143. package/src/electron/utils/onedrive-api.ts +137 -0
  144. package/src/electron/utils/sharepoint-api.ts +132 -0
  145. package/src/electron/utils/validation.ts +102 -1
  146. package/src/electron/utils/x-cli.ts +1 -1
  147. package/src/renderer/App.tsx +20 -2
  148. package/src/renderer/components/BoxSettings.tsx +203 -0
  149. package/src/renderer/components/BrowserView.tsx +101 -0
  150. package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
  151. package/src/renderer/components/CanvasPreview.tsx +68 -1
  152. package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
  153. package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
  154. package/src/renderer/components/ConnectorsSettings.tsx +397 -0
  155. package/src/renderer/components/DropboxSettings.tsx +202 -0
  156. package/src/renderer/components/GoogleDriveSettings.tsx +201 -0
  157. package/src/renderer/components/MCPSettings.tsx +56 -0
  158. package/src/renderer/components/MainContent.tsx +270 -34
  159. package/src/renderer/components/NotionSettings.tsx +231 -0
  160. package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
  161. package/src/renderer/components/OnboardingModal.tsx +70 -1
  162. package/src/renderer/components/OneDriveSettings.tsx +212 -0
  163. package/src/renderer/components/Settings.tsx +611 -8
  164. package/src/renderer/components/SharePointSettings.tsx +224 -0
  165. package/src/renderer/components/Sidebar.tsx +25 -9
  166. package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
  167. package/src/renderer/styles/index.css +438 -25
  168. package/src/shared/channelMessages.ts +367 -4
  169. package/src/shared/llm-provider-catalog.ts +217 -0
  170. package/src/shared/types.ts +226 -1
@@ -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,14 @@ 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
+
66
75
  // ============ Approval Schemas ============
67
76
 
68
77
  export const ApprovalResponseSchema = z.object({
@@ -72,7 +81,7 @@ export const ApprovalResponseSchema = z.object({
72
81
 
73
82
  // ============ LLM Settings Schemas ============
74
83
 
75
- export const LLMProviderTypeSchema = z.enum(['anthropic', 'bedrock', 'ollama', 'gemini', 'openrouter', 'openai']);
84
+ export const LLMProviderTypeSchema = z.enum(LLM_PROVIDER_TYPES);
76
85
 
77
86
  export const AnthropicSettingsSchema = z.object({
78
87
  apiKey: z.string().max(500).optional(),
@@ -102,6 +111,7 @@ export const GeminiSettingsSchema = z.object({
102
111
  export const OpenRouterSettingsSchema = z.object({
103
112
  apiKey: z.string().max(500).optional(),
104
113
  model: z.string().max(200).optional(),
114
+ baseUrl: z.string().max(500).optional(),
105
115
  }).optional();
106
116
 
107
117
  export const OpenAISettingsSchema = z.object({
@@ -114,6 +124,32 @@ export const OpenAISettingsSchema = z.object({
114
124
  authMethod: z.enum(['api_key', 'oauth']).optional(),
115
125
  }).optional();
116
126
 
127
+ export const GroqSettingsSchema = z.object({
128
+ apiKey: z.string().max(500).optional(),
129
+ model: z.string().max(200).optional(),
130
+ baseUrl: z.string().max(500).optional(),
131
+ }).optional();
132
+
133
+ export const XAISettingsSchema = z.object({
134
+ apiKey: z.string().max(500).optional(),
135
+ model: z.string().max(200).optional(),
136
+ baseUrl: z.string().max(500).optional(),
137
+ }).optional();
138
+
139
+ export const KimiSettingsSchema = z.object({
140
+ apiKey: z.string().max(500).optional(),
141
+ model: z.string().max(200).optional(),
142
+ baseUrl: z.string().max(500).optional(),
143
+ }).optional();
144
+
145
+ export const CustomProviderConfigSchema = z.object({
146
+ apiKey: z.string().max(500).optional(),
147
+ model: z.string().max(200).optional(),
148
+ baseUrl: z.string().max(500).optional(),
149
+ });
150
+
151
+ export const CustomProvidersSchema = z.record(z.string(), CustomProviderConfigSchema).optional();
152
+
117
153
  export const LLMSettingsSchema = z.object({
118
154
  providerType: LLMProviderTypeSchema,
119
155
  modelKey: z.string().max(200),
@@ -123,6 +159,10 @@ export const LLMSettingsSchema = z.object({
123
159
  gemini: GeminiSettingsSchema,
124
160
  openrouter: OpenRouterSettingsSchema,
125
161
  openai: OpenAISettingsSchema,
162
+ groq: GroqSettingsSchema,
163
+ xai: XAISettingsSchema,
164
+ kimi: KimiSettingsSchema,
165
+ customProviders: CustomProvidersSchema,
126
166
  });
127
167
 
128
168
  // ============ Search Settings Schemas ============
@@ -163,6 +203,58 @@ export const XSettingsSchema = z.object({
163
203
  quoteDepth: z.number().int().min(0).max(5).optional(),
164
204
  });
165
205
 
206
+ // ============ Notion Settings Schema ============
207
+
208
+ export const NotionSettingsSchema = z.object({
209
+ enabled: z.boolean().default(false),
210
+ apiKey: z.string().max(2000).optional(),
211
+ notionVersion: z.string().max(50).optional(),
212
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
213
+ });
214
+
215
+ // ============ Box Settings Schema ============
216
+
217
+ export const BoxSettingsSchema = z.object({
218
+ enabled: z.boolean().default(false),
219
+ accessToken: z.string().max(4000).optional(),
220
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
221
+ });
222
+
223
+ // ============ OneDrive Settings Schema ============
224
+
225
+ export const OneDriveSettingsSchema = z.object({
226
+ enabled: z.boolean().default(false),
227
+ accessToken: z.string().max(4000).optional(),
228
+ driveId: z.string().max(200).optional(),
229
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
230
+ });
231
+
232
+ // ============ Google Drive Settings Schema ============
233
+
234
+ export const GoogleDriveSettingsSchema = z.object({
235
+ enabled: z.boolean().default(false),
236
+ accessToken: z.string().max(4000).optional(),
237
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
238
+ });
239
+
240
+ // ============ Dropbox Settings Schema ============
241
+
242
+ export const DropboxSettingsSchema = z.object({
243
+ enabled: z.boolean().default(false),
244
+ accessToken: z.string().max(4000).optional(),
245
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
246
+ });
247
+
248
+ // ============ SharePoint Settings Schema ============
249
+
250
+ export const SharePointSettingsSchema = z.object({
251
+ enabled: z.boolean().default(false),
252
+ accessToken: z.string().max(4000).optional(),
253
+ siteId: z.string().max(500).optional(),
254
+ driveId: z.string().max(500).optional(),
255
+ timeoutMs: z.number().int().min(1000).max(120000).optional(),
256
+ });
257
+
166
258
  // ============ Guardrail Settings Schema ============
167
259
 
168
260
  export const GuardrailSettingsSchema = z.object({
@@ -451,6 +543,15 @@ export const MCPRegistrySearchSchema = z.object({
451
543
  offset: z.number().int().min(0).default(0),
452
544
  });
453
545
 
546
+ export const MCPConnectorOAuthSchema = z.object({
547
+ provider: z.enum(['salesforce', 'jira', 'hubspot', 'zendesk']),
548
+ clientId: z.string().min(1).max(500),
549
+ clientSecret: z.string().max(500).optional(),
550
+ scopes: z.array(z.string().max(200)).max(50).optional(),
551
+ loginUrl: z.string().url().max(500).optional(),
552
+ subdomain: z.string().max(200).optional(),
553
+ });
554
+
454
555
  // ============ Hooks (Webhooks) Schemas ============
455
556
 
456
557
  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 {
@@ -5,6 +5,7 @@ import { RightPanel } from './components/RightPanel';
5
5
  import { Settings } from './components/Settings';
6
6
  import { DisclaimerModal } from './components/DisclaimerModal';
7
7
  import { Onboarding } from './components/Onboarding';
8
+ import { BrowserView } from './components/BrowserView';
8
9
  // TaskQueuePanel moved to RightPanel
9
10
  import { ToastContainer } from './components/Toast';
10
11
  import { QuickTaskFAB } from './components/QuickTaskFAB';
@@ -20,14 +21,15 @@ function getEffectiveTheme(themeMode: ThemeMode): 'light' | 'dark' {
20
21
  return themeMode;
21
22
  }
22
23
 
23
- type AppView = 'main' | 'settings';
24
+ type AppView = 'main' | 'settings' | 'browser';
24
25
 
25
26
  export function App() {
26
27
  const [currentWorkspace, setCurrentWorkspace] = useState<Workspace | null>(null);
27
28
  const [tasks, setTasks] = useState<Task[]>([]);
28
29
  const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
29
30
  const [currentView, setCurrentView] = useState<AppView>('main');
30
- const [settingsTab, setSettingsTab] = useState<'appearance' | 'llm' | 'search' | 'telegram' | 'slack' | 'whatsapp' | 'teams' | 'morechannels' | 'updates' | 'guardrails' | 'queue' | 'skills' | 'scheduled' | 'voice'>('appearance');
31
+ const [browserUrl, setBrowserUrl] = useState<string>('');
32
+ const [settingsTab, setSettingsTab] = useState<'appearance' | 'llm' | 'search' | 'telegram' | 'slack' | 'whatsapp' | 'teams' | 'x' | 'morechannels' | 'integrations' | 'updates' | 'guardrails' | 'queue' | 'skills' | 'scheduled' | 'voice' | 'missioncontrol'>('appearance');
31
33
  const [events, setEvents] = useState<TaskEvent[]>([]);
32
34
 
33
35
  // Model selection state
@@ -82,6 +84,11 @@ export function App() {
82
84
  loadLLMConfig();
83
85
  };
84
86
 
87
+ const handleOpenBrowserView = (url?: string) => {
88
+ setBrowserUrl(url || '');
89
+ setCurrentView('browser');
90
+ };
91
+
85
92
  const handleShowOnboarding = () => {
86
93
  // Reset onboarding state to show the wizard again
87
94
  setOnboardingCompleted(false);
@@ -710,6 +717,10 @@ export function App() {
710
717
  selectedTaskId={selectedTaskId}
711
718
  onSelectTask={setSelectedTaskId}
712
719
  onOpenSettings={() => setCurrentView('settings')}
720
+ onOpenMissionControl={() => {
721
+ setSettingsTab('missioncontrol');
722
+ setCurrentView('settings');
723
+ }}
713
724
  onTasksChanged={loadTasks}
714
725
  />
715
726
  )}
@@ -727,6 +738,7 @@ export function App() {
727
738
  setCurrentView('settings');
728
739
  }}
729
740
  onStopTask={handleCancelTask}
741
+ onOpenBrowserView={handleOpenBrowserView}
730
742
  selectedModel={selectedModel}
731
743
  availableModels={availableModels}
732
744
  onModelChange={handleModelChange}
@@ -770,6 +782,12 @@ export function App() {
770
782
  onboardingCompletedAt={onboardingCompletedAt}
771
783
  />
772
784
  )}
785
+ {currentView === 'browser' && (
786
+ <BrowserView
787
+ initialUrl={browserUrl}
788
+ onBack={() => setCurrentView('main')}
789
+ />
790
+ )}
773
791
  </div>
774
792
  );
775
793
  }