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.
- package/README.md +372 -10
- package/connectors/README.md +20 -0
- package/connectors/asana-mcp/README.md +24 -0
- package/connectors/asana-mcp/dist/index.js +427 -0
- package/connectors/asana-mcp/package.json +15 -0
- package/connectors/asana-mcp/src/index.ts +553 -0
- package/connectors/asana-mcp/tsconfig.json +13 -0
- package/connectors/hubspot-mcp/README.md +35 -0
- package/connectors/hubspot-mcp/dist/index.js +454 -0
- package/connectors/hubspot-mcp/package.json +15 -0
- package/connectors/hubspot-mcp/src/index.ts +562 -0
- package/connectors/hubspot-mcp/tsconfig.json +13 -0
- package/connectors/jira-mcp/README.md +49 -0
- package/connectors/jira-mcp/dist/index.js +588 -0
- package/connectors/jira-mcp/package.json +15 -0
- package/connectors/jira-mcp/src/index.ts +711 -0
- package/connectors/jira-mcp/tsconfig.json +13 -0
- package/connectors/linear-mcp/README.md +22 -0
- package/connectors/linear-mcp/dist/index.js +402 -0
- package/connectors/linear-mcp/package.json +15 -0
- package/connectors/linear-mcp/src/index.ts +522 -0
- package/connectors/linear-mcp/tsconfig.json +13 -0
- package/connectors/okta-mcp/README.md +24 -0
- package/connectors/okta-mcp/dist/index.js +411 -0
- package/connectors/okta-mcp/package.json +15 -0
- package/connectors/okta-mcp/src/index.ts +520 -0
- package/connectors/okta-mcp/tsconfig.json +13 -0
- package/connectors/salesforce-mcp/README.md +47 -0
- package/connectors/salesforce-mcp/dist/index.js +584 -0
- package/connectors/salesforce-mcp/package.json +15 -0
- package/connectors/salesforce-mcp/src/index.ts +722 -0
- package/connectors/salesforce-mcp/tsconfig.json +13 -0
- package/connectors/servicenow-mcp/README.md +26 -0
- package/connectors/servicenow-mcp/dist/index.js +400 -0
- package/connectors/servicenow-mcp/package.json +15 -0
- package/connectors/servicenow-mcp/src/index.ts +500 -0
- package/connectors/servicenow-mcp/tsconfig.json +13 -0
- package/connectors/templates/mcp-connector/README.md +31 -0
- package/connectors/templates/mcp-connector/package.json +15 -0
- package/connectors/templates/mcp-connector/src/index.ts +330 -0
- package/connectors/templates/mcp-connector/tsconfig.json +13 -0
- package/connectors/zendesk-mcp/README.md +40 -0
- package/connectors/zendesk-mcp/dist/index.js +431 -0
- package/connectors/zendesk-mcp/package.json +15 -0
- package/connectors/zendesk-mcp/src/index.ts +543 -0
- package/connectors/zendesk-mcp/tsconfig.json +13 -0
- package/dist/electron/electron/agent/custom-skill-loader.js +31 -1
- package/dist/electron/electron/agent/daemon.js +189 -13
- package/dist/electron/electron/agent/executor.js +895 -78
- package/dist/electron/electron/agent/llm/anthropic-compatible-provider.js +177 -0
- package/dist/electron/electron/agent/llm/azure-openai-provider.js +328 -0
- package/dist/electron/electron/agent/llm/bedrock-provider.js +49 -9
- package/dist/electron/electron/agent/llm/github-copilot-provider.js +97 -0
- package/dist/electron/electron/agent/llm/groq-provider.js +33 -0
- package/dist/electron/electron/agent/llm/index.js +13 -1
- package/dist/electron/electron/agent/llm/kimi-provider.js +33 -0
- package/dist/electron/electron/agent/llm/openai-compatible-provider.js +116 -0
- package/dist/electron/electron/agent/llm/openai-compatible.js +111 -0
- package/dist/electron/electron/agent/llm/openai-oauth.js +2 -1
- package/dist/electron/electron/agent/llm/openrouter-provider.js +1 -1
- package/dist/electron/electron/agent/llm/provider-factory.js +350 -4
- package/dist/electron/electron/agent/llm/types.js +66 -1
- package/dist/electron/electron/agent/llm/xai-provider.js +33 -0
- package/dist/electron/electron/agent/search/provider-factory.js +38 -2
- package/dist/electron/electron/agent/tools/box-tools.js +231 -0
- package/dist/electron/electron/agent/tools/builtin-settings.js +28 -0
- package/dist/electron/electron/agent/tools/dropbox-tools.js +237 -0
- package/dist/electron/electron/agent/tools/file-tools.js +66 -3
- package/dist/electron/electron/agent/tools/google-drive-tools.js +227 -0
- package/dist/electron/electron/agent/tools/grep-tools.js +90 -10
- package/dist/electron/electron/agent/tools/image-tools.js +11 -1
- package/dist/electron/electron/agent/tools/notion-tools.js +312 -0
- package/dist/electron/electron/agent/tools/onedrive-tools.js +217 -0
- package/dist/electron/electron/agent/tools/registry.js +548 -10
- package/dist/electron/electron/agent/tools/search-tools.js +28 -10
- package/dist/electron/electron/agent/tools/sharepoint-tools.js +243 -0
- package/dist/electron/electron/agent/tools/shell-tools.js +12 -3
- package/dist/electron/electron/agent/tools/x-tools.js +1 -1
- package/dist/electron/electron/agents/agent-dispatch.js +63 -0
- package/dist/electron/electron/database/repositories.js +19 -5
- package/dist/electron/electron/database/schema.js +8 -0
- package/dist/electron/electron/gateway/channels/whatsapp.js +55 -0
- package/dist/electron/electron/gateway/index.js +75 -1
- package/dist/electron/electron/gateway/router.js +209 -154
- package/dist/electron/electron/ipc/canvas-handlers.js +5 -0
- package/dist/electron/electron/ipc/handlers.js +763 -267
- package/dist/electron/electron/main.js +63 -0
- package/dist/electron/electron/mcp/oauth/connector-oauth.js +333 -0
- package/dist/electron/electron/mcp/registry/MCPRegistryManager.js +503 -154
- package/dist/electron/electron/memory/MemoryService.js +2 -1
- package/dist/electron/electron/preload.js +78 -1
- package/dist/electron/electron/settings/appearance-manager.js +18 -1
- package/dist/electron/electron/settings/box-manager.js +54 -0
- package/dist/electron/electron/settings/dropbox-manager.js +54 -0
- package/dist/electron/electron/settings/google-drive-manager.js +54 -0
- package/dist/electron/electron/settings/notion-manager.js +56 -0
- package/dist/electron/electron/settings/onedrive-manager.js +54 -0
- package/dist/electron/electron/settings/sharepoint-manager.js +54 -0
- package/dist/electron/electron/utils/box-api.js +153 -0
- package/dist/electron/electron/utils/dropbox-api.js +144 -0
- package/dist/electron/electron/utils/env-migration.js +19 -0
- package/dist/electron/electron/utils/google-drive-api.js +152 -0
- package/dist/electron/electron/utils/notion-api.js +103 -0
- package/dist/electron/electron/utils/onedrive-api.js +113 -0
- package/dist/electron/electron/utils/sharepoint-api.js +109 -0
- package/dist/electron/electron/utils/validation.js +98 -3
- package/dist/electron/electron/utils/x-cli.js +1 -1
- package/dist/electron/shared/channelMessages.js +284 -3
- package/dist/electron/shared/llm-provider-catalog.js +198 -0
- package/dist/electron/shared/types.js +90 -1
- package/package.json +14 -3
- package/resources/skills/nano-banana-pro.json +4 -4
- package/resources/skills/openai-image-gen.json +3 -3
- package/resources/skills/scripts/gen.py +163 -0
- package/resources/skills/scripts/generate_image.py +91 -0
- package/src/electron/agent/custom-skill-loader.ts +34 -1
- package/src/electron/agent/daemon.ts +210 -14
- package/src/electron/agent/executor.ts +1124 -85
- package/src/electron/agent/llm/anthropic-compatible-provider.ts +214 -0
- package/src/electron/agent/llm/azure-openai-provider.ts +388 -0
- package/src/electron/agent/llm/bedrock-provider.ts +62 -9
- package/src/electron/agent/llm/github-copilot-provider.ts +117 -0
- package/src/electron/agent/llm/groq-provider.ts +39 -0
- package/src/electron/agent/llm/index.ts +6 -0
- package/src/electron/agent/llm/kimi-provider.ts +39 -0
- package/src/electron/agent/llm/openai-compatible-provider.ts +153 -0
- package/src/electron/agent/llm/openai-compatible.ts +133 -0
- package/src/electron/agent/llm/openai-oauth.ts +2 -1
- package/src/electron/agent/llm/openrouter-provider.ts +2 -1
- package/src/electron/agent/llm/provider-factory.ts +459 -6
- package/src/electron/agent/llm/types.ts +95 -1
- package/src/electron/agent/llm/xai-provider.ts +39 -0
- package/src/electron/agent/search/provider-factory.ts +43 -2
- package/src/electron/agent/tools/box-tools.ts +239 -0
- package/src/electron/agent/tools/builtin-settings.ts +36 -0
- package/src/electron/agent/tools/dropbox-tools.ts +237 -0
- package/src/electron/agent/tools/file-tools.ts +66 -3
- package/src/electron/agent/tools/gmail-tools.ts +240 -0
- package/src/electron/agent/tools/google-calendar-tools.ts +258 -0
- package/src/electron/agent/tools/google-drive-tools.ts +228 -0
- package/src/electron/agent/tools/grep-tools.ts +97 -12
- package/src/electron/agent/tools/image-tools.ts +11 -1
- package/src/electron/agent/tools/notion-tools.ts +330 -0
- package/src/electron/agent/tools/onedrive-tools.ts +217 -0
- package/src/electron/agent/tools/registry.ts +794 -10
- package/src/electron/agent/tools/search-tools.ts +29 -11
- package/src/electron/agent/tools/sharepoint-tools.ts +247 -0
- package/src/electron/agent/tools/shell-tools.ts +11 -3
- package/src/electron/agent/tools/x-tools.ts +1 -1
- package/src/electron/agents/agent-dispatch.ts +79 -0
- package/src/electron/database/SecureSettingsRepository.ts +7 -1
- package/src/electron/database/repositories.ts +58 -6
- package/src/electron/database/schema.ts +8 -0
- package/src/electron/gateway/channels/discord.ts +4 -0
- package/src/electron/gateway/channels/google-chat.ts +3 -0
- package/src/electron/gateway/channels/line.ts +3 -0
- package/src/electron/gateway/channels/matrix-client.ts +15 -0
- package/src/electron/gateway/channels/matrix.ts +31 -0
- package/src/electron/gateway/channels/mattermost.ts +3 -0
- package/src/electron/gateway/channels/signal.ts +3 -0
- package/src/electron/gateway/channels/slack.ts +9 -4
- package/src/electron/gateway/channels/teams.ts +4 -0
- package/src/electron/gateway/channels/telegram.ts +2 -0
- package/src/electron/gateway/channels/twitch.ts +2 -0
- package/src/electron/gateway/channels/types.ts +8 -0
- package/src/electron/gateway/channels/whatsapp.ts +66 -0
- package/src/electron/gateway/index.ts +95 -2
- package/src/electron/gateway/router.ts +231 -161
- package/src/electron/gateway/security.ts +21 -9
- package/src/electron/ipc/canvas-handlers.ts +10 -0
- package/src/electron/ipc/handlers.ts +848 -292
- package/src/electron/main.ts +35 -0
- package/src/electron/mcp/oauth/connector-oauth.ts +448 -0
- package/src/electron/mcp/registry/MCPRegistryManager.ts +343 -12
- package/src/electron/memory/MemoryService.ts +7 -1
- package/src/electron/preload.ts +200 -5
- package/src/electron/settings/appearance-manager.ts +20 -2
- package/src/electron/settings/box-manager.ts +58 -0
- package/src/electron/settings/dropbox-manager.ts +58 -0
- package/src/electron/settings/google-workspace-manager.ts +59 -0
- package/src/electron/settings/notion-manager.ts +60 -0
- package/src/electron/settings/onedrive-manager.ts +58 -0
- package/src/electron/settings/sharepoint-manager.ts +58 -0
- package/src/electron/utils/box-api.ts +184 -0
- package/src/electron/utils/dropbox-api.ts +171 -0
- package/src/electron/utils/env-migration.ts +22 -0
- package/src/electron/utils/gmail-api.ts +121 -0
- package/src/electron/utils/google-calendar-api.ts +115 -0
- package/src/electron/utils/google-workspace-api.ts +228 -0
- package/src/electron/utils/google-workspace-auth.ts +109 -0
- package/src/electron/utils/google-workspace-oauth.ts +232 -0
- package/src/electron/utils/notion-api.ts +126 -0
- package/src/electron/utils/onedrive-api.ts +137 -0
- package/src/electron/utils/sharepoint-api.ts +132 -0
- package/src/electron/utils/validation.ts +128 -1
- package/src/electron/utils/x-cli.ts +1 -1
- package/src/renderer/App.tsx +119 -8
- package/src/renderer/components/ActivityFeedItem.tsx +34 -17
- package/src/renderer/components/AgentWorkingStatePanel.tsx +7 -5
- package/src/renderer/components/AppearanceSettings.tsx +37 -2
- package/src/renderer/components/BlueBubblesSettings.tsx +18 -7
- package/src/renderer/components/BoxSettings.tsx +203 -0
- package/src/renderer/components/BrowserView.tsx +101 -0
- package/src/renderer/components/BuiltinToolsSettings.tsx +105 -0
- package/src/renderer/components/CanvasPreview.tsx +68 -1
- package/src/renderer/components/ConnectorEnvModal.tsx +116 -0
- package/src/renderer/components/ConnectorSetupModal.tsx +566 -0
- package/src/renderer/components/ConnectorsSettings.tsx +397 -0
- package/src/renderer/components/ControlPlaneSettings.tsx +2 -0
- package/src/renderer/components/DiscordSettings.tsx +18 -7
- package/src/renderer/components/DropboxSettings.tsx +202 -0
- package/src/renderer/components/EmailSettings.tsx +18 -7
- package/src/renderer/components/FileViewer.tsx +21 -13
- package/src/renderer/components/GoogleChatSettings.tsx +17 -7
- package/src/renderer/components/GoogleWorkspaceSettings.tsx +332 -0
- package/src/renderer/components/ImessageSettings.tsx +22 -11
- package/src/renderer/components/LineIcons.tsx +376 -0
- package/src/renderer/components/LineSettings.tsx +18 -7
- package/src/renderer/components/MCPSettings.tsx +56 -0
- package/src/renderer/components/MainContent.tsx +740 -76
- package/src/renderer/components/MatrixSettings.tsx +18 -7
- package/src/renderer/components/MattermostSettings.tsx +18 -7
- package/src/renderer/components/NodesSettings.tsx +58 -99
- package/src/renderer/components/NotificationPanel.tsx +25 -11
- package/src/renderer/components/NotionSettings.tsx +231 -0
- package/src/renderer/components/Onboarding/Onboarding.tsx +13 -1
- package/src/renderer/components/OnboardingModal.tsx +70 -1
- package/src/renderer/components/OneDriveSettings.tsx +212 -0
- package/src/renderer/components/RightPanel.tsx +141 -28
- package/src/renderer/components/ScheduledTasksSettings.tsx +10 -62
- package/src/renderer/components/SearchSettings.tsx +118 -114
- package/src/renderer/components/Settings.tsx +1425 -651
- package/src/renderer/components/SharePointSettings.tsx +224 -0
- package/src/renderer/components/Sidebar.tsx +94 -19
- package/src/renderer/components/SignalSettings.tsx +18 -7
- package/src/renderer/components/SkillHubBrowser.tsx +144 -185
- package/src/renderer/components/SlackSettings.tsx +18 -7
- package/src/renderer/components/TaskQuickActions.tsx +11 -6
- package/src/renderer/components/TaskTimeline.tsx +58 -26
- package/src/renderer/components/TeamsSettings.tsx +18 -7
- package/src/renderer/components/TelegramSettings.tsx +18 -7
- package/src/renderer/components/ThemeIcon.tsx +16 -0
- package/src/renderer/components/TwitchSettings.tsx +18 -7
- package/src/renderer/components/VoiceSettings.tsx +30 -74
- package/src/renderer/components/WhatsAppSettings.tsx +48 -37
- package/src/renderer/components/WorkingStateHistory.tsx +7 -5
- package/src/renderer/components/WorkspaceSelector.tsx +42 -13
- package/src/renderer/hooks/useOnboardingFlow.ts +21 -0
- package/src/renderer/styles/index.css +2333 -209
- package/src/shared/channelMessages.ts +367 -4
- package/src/shared/llm-provider-catalog.ts +217 -0
- 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(
|
|
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 >
|
|
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 {
|