@agent-native/core 0.104.0 → 0.106.0
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +64 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/AssistantChat.tsx +4 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +5 -1
- package/corpus/core/src/client/composer/PromptComposer.tsx +8 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +38 -1
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +107 -32
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +33 -0
- package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
- package/corpus/core/src/client/use-chat-models.ts +10 -2
- package/corpus/core/src/connections/catalog.ts +107 -6
- package/corpus/core/src/deploy/build.ts +23 -0
- package/corpus/core/src/localization/default-messages.ts +2 -0
- package/corpus/core/src/mcp/actions/call-mcp-tool.ts +18 -0
- package/corpus/core/src/mcp/actions/list-mcp-tools.ts +18 -0
- package/corpus/core/src/mcp-client/app-api.ts +136 -0
- package/corpus/core/src/mcp-client/index.ts +21 -0
- package/corpus/core/src/mcp-client/oauth-client.ts +462 -0
- package/corpus/core/src/mcp-client/oauth-routes.ts +307 -0
- package/corpus/core/src/mcp-client/remote-store.ts +93 -118
- package/corpus/core/src/mcp-client/remote-url.ts +97 -0
- package/corpus/core/src/mcp-client/routes.ts +11 -0
- package/corpus/core/src/oauth-tokens/store.ts +10 -4
- package/corpus/core/src/provider-api/index.ts +690 -55
- package/corpus/core/src/secrets/register-framework-secrets.ts +30 -0
- package/corpus/core/src/server/action-discovery.ts +2 -0
- package/corpus/core/src/server/core-routes-plugin.ts +9 -1
- package/corpus/core/src/server/workspace-provider-oauth.ts +448 -61
- package/corpus/core/src/templates/default/AGENTS.md +9 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +61 -0
- package/corpus/templates/analytics/server/handlers/jira.ts +7 -0
- package/corpus/templates/analytics/server/lib/jira.ts +14 -42
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +11 -0
- package/corpus/templates/clips/app/routes.ts +3 -1
- package/corpus/templates/dispatch/app/routes/integrations.tsx +57 -4
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +5 -2
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts +2 -0
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +5 -2
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +4 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +13 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +58 -14
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts +9 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +13 -0
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/use-chat-models.d.ts +1 -0
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +8 -2
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +78 -7
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +97 -6
- package/dist/connections/catalog.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +17 -0
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +2 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/actions/call-mcp-tool.d.ts +7 -0
- package/dist/mcp/actions/call-mcp-tool.d.ts.map +1 -0
- package/dist/mcp/actions/call-mcp-tool.js +15 -0
- package/dist/mcp/actions/call-mcp-tool.js.map +1 -0
- package/dist/mcp/actions/list-mcp-tools.d.ts +5 -0
- package/dist/mcp/actions/list-mcp-tools.d.ts.map +1 -0
- package/dist/mcp/actions/list-mcp-tools.js +16 -0
- package/dist/mcp/actions/list-mcp-tools.js.map +1 -0
- package/dist/mcp-client/app-api.d.ts +34 -0
- package/dist/mcp-client/app-api.d.ts.map +1 -0
- package/dist/mcp-client/app-api.js +94 -0
- package/dist/mcp-client/app-api.js.map +1 -0
- package/dist/mcp-client/index.d.ts +3 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +3 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/oauth-client.d.ts +113 -0
- package/dist/mcp-client/oauth-client.d.ts.map +1 -0
- package/dist/mcp-client/oauth-client.js +316 -0
- package/dist/mcp-client/oauth-client.js.map +1 -0
- package/dist/mcp-client/oauth-routes.d.ts +25 -0
- package/dist/mcp-client/oauth-routes.d.ts.map +1 -0
- package/dist/mcp-client/oauth-routes.js +218 -0
- package/dist/mcp-client/oauth-routes.js.map +1 -0
- package/dist/mcp-client/remote-store.d.ts +21 -6
- package/dist/mcp-client/remote-store.d.ts.map +1 -1
- package/dist/mcp-client/remote-store.js +72 -124
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/mcp-client/remote-url.d.ts +8 -0
- package/dist/mcp-client/remote-url.d.ts.map +1 -0
- package/dist/mcp-client/remote-url.js +103 -0
- package/dist/mcp-client/remote-url.js.map +1 -0
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +9 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/oauth-tokens/store.d.ts +2 -2
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +10 -6
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/index.d.ts +14 -0
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +499 -61
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +28 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +2 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +9 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/workspace-provider-oauth.d.ts +10 -3
- package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
- package/dist/server/workspace-provider-oauth.js +325 -43
- package/dist/server/workspace-provider-oauth.js.map +1 -1
- package/dist/templates/default/AGENTS.md +9 -7
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
- package/package.json +2 -2
- package/src/templates/default/AGENTS.md +9 -7
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
|
@@ -68,6 +68,52 @@ the real app focused on exactly what was produced. It reuses the existing
|
|
|
68
68
|
`navigate` / `application_state` contract the UI already drains every 2s (see
|
|
69
69
|
**context-awareness**) — we never invent a second navigation mechanism.
|
|
70
70
|
|
|
71
|
+
## App-facing MCP connectors
|
|
72
|
+
|
|
73
|
+
Apps can also consume connected remote MCP servers as a server-side API. The
|
|
74
|
+
framework stores each connector's OAuth client registration, discovery metadata,
|
|
75
|
+
access token, and refresh token in the encrypted `oauth_tokens` store, scoped to
|
|
76
|
+
the user or organization. The browser and sandboxed MCP App iframes never
|
|
77
|
+
receive those credentials.
|
|
78
|
+
|
|
79
|
+
Use the hidden core actions `list-mcp-tools` and `call-mcp-tool` when an app UI
|
|
80
|
+
needs a request-scoped API surface. Server-side app actions can import
|
|
81
|
+
`listVisibleMcpTools` and `callMcpTool` from `@agent-native/core/mcp-client`.
|
|
82
|
+
Both paths require an authenticated request context and enforce user/org server
|
|
83
|
+
visibility plus MCP App visibility metadata. Pass the configured server id and
|
|
84
|
+
the server's original tool name; the framework resolves the internal prefixed
|
|
85
|
+
tool name and injects the connector's bearer token.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { callMcpTool } from "@agent-native/core/mcp-client";
|
|
89
|
+
|
|
90
|
+
const result = await callMcpTool("org_acme_linear", "list_issues", {
|
|
91
|
+
project: "<PROJECT_ID>",
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use this for bounded product workflows (for example, syncing issues or
|
|
96
|
+
refreshing analytics). Do not expose a raw token, arbitrary server URL, or
|
|
97
|
+
unbounded proxy from an app action. Keep provider-specific schemas and access
|
|
98
|
+
checks in the app action, and use the connector catalog/OAuth button for setup.
|
|
99
|
+
|
|
100
|
+
## Provider API connectors
|
|
101
|
+
|
|
102
|
+
The shared workspace connection catalog is also the setup surface for provider
|
|
103
|
+
APIs. When a provider advertises OAuth, show that connection as the primary
|
|
104
|
+
setup action and retain its API key or token as an explicit fallback. Current
|
|
105
|
+
shared OAuth providers include Figma, GitHub, Google Drive, HubSpot, Jira Cloud, Notion, and Sentry. Slack
|
|
106
|
+
uses its managed messaging-install OAuth flow. Gmail,
|
|
107
|
+
Calendar, and Slides may use template-owned Google OAuth flows with broader
|
|
108
|
+
scopes; do not replace those flows with the narrower Drive connection.
|
|
109
|
+
|
|
110
|
+
Provider API actions resolve credentials server-side. Pass a granted
|
|
111
|
+
`connectionId` when a request must use a particular OAuth account; never copy
|
|
112
|
+
the access token into a browser, extension, MCP App, prompt, or stored action
|
|
113
|
+
payload. Key-only providers should remain in the normal scoped secrets flow
|
|
114
|
+
until their upstream OAuth app, scopes, refresh behavior, and identity mapping
|
|
115
|
+
have been implemented and configured.
|
|
116
|
+
|
|
71
117
|
## How
|
|
72
118
|
|
|
73
119
|
### 1. Connect to hosted apps
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
IconCopy,
|
|
27
27
|
IconDotsVertical,
|
|
28
28
|
IconBrandGithub,
|
|
29
|
+
IconPlugConnected,
|
|
29
30
|
} from "@tabler/icons-react";
|
|
30
31
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
31
32
|
import { useEffect, useState } from "react";
|
|
@@ -427,6 +428,55 @@ function GitHubOAuthView({
|
|
|
427
428
|
);
|
|
428
429
|
}
|
|
429
430
|
|
|
431
|
+
function WorkspaceOAuthView({
|
|
432
|
+
provider,
|
|
433
|
+
label,
|
|
434
|
+
connected,
|
|
435
|
+
}: {
|
|
436
|
+
provider: string;
|
|
437
|
+
label: string;
|
|
438
|
+
connected: boolean;
|
|
439
|
+
}) {
|
|
440
|
+
const t = useT();
|
|
441
|
+
const connect = () => {
|
|
442
|
+
const params = new URLSearchParams({
|
|
443
|
+
appId: "analytics",
|
|
444
|
+
return: "/data-sources",
|
|
445
|
+
});
|
|
446
|
+
window.location.assign(
|
|
447
|
+
agentNativePath(
|
|
448
|
+
`/_agent-native/connections/oauth/${provider}/start?${params.toString()}`,
|
|
449
|
+
),
|
|
450
|
+
);
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
return (
|
|
454
|
+
<div className="space-y-3 rounded-md border border-border/50 bg-muted/20 p-3">
|
|
455
|
+
<div className="flex items-start justify-between gap-3">
|
|
456
|
+
<div className="flex items-start gap-3">
|
|
457
|
+
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-background text-muted-foreground">
|
|
458
|
+
<IconPlugConnected className="h-4 w-4" />
|
|
459
|
+
</div>
|
|
460
|
+
<div className="min-w-0 space-y-1">
|
|
461
|
+
<p className="text-xs font-medium text-foreground">{label}</p>
|
|
462
|
+
<p className="text-xs text-muted-foreground">
|
|
463
|
+
{t("dataSources.sharedIntegration")}
|
|
464
|
+
</p>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
<Button
|
|
468
|
+
size="sm"
|
|
469
|
+
variant={connected ? "outline" : "default"}
|
|
470
|
+
onClick={connect}
|
|
471
|
+
className="shrink-0 text-xs"
|
|
472
|
+
>
|
|
473
|
+
{connected ? t("dataSources.reconnect") : t("dataSources.connect")}
|
|
474
|
+
</Button>
|
|
475
|
+
</div>
|
|
476
|
+
</div>
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
430
480
|
function SharedConnectionBadge({ status }: { status: SharedConnectionStatus }) {
|
|
431
481
|
const tone =
|
|
432
482
|
status.kind === "ready"
|
|
@@ -1101,6 +1151,17 @@ function DataSourceCard({
|
|
|
1101
1151
|
/>
|
|
1102
1152
|
</div>
|
|
1103
1153
|
)}
|
|
1154
|
+
{(["notion", "hubspot", "jira", "sentry"] as const).includes(
|
|
1155
|
+
source.id as "notion" | "hubspot" | "jira" | "sentry",
|
|
1156
|
+
) && (
|
|
1157
|
+
<div className="mb-4">
|
|
1158
|
+
<WorkspaceOAuthView
|
|
1159
|
+
provider={source.id}
|
|
1160
|
+
label={source.name}
|
|
1161
|
+
connected={readyViaWorkspace}
|
|
1162
|
+
/>
|
|
1163
|
+
</div>
|
|
1164
|
+
)}
|
|
1104
1165
|
{sharedConnectionStatus && (
|
|
1105
1166
|
<SharedConnectionStatusRow status={sharedConnectionStatus} />
|
|
1106
1167
|
)}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveWorkspaceConnectionForApp } from "@agent-native/core/workspace-connections";
|
|
1
2
|
import { defineEventHandler, getQuery, setResponseStatus } from "h3";
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -17,6 +18,12 @@ import {
|
|
|
17
18
|
async function requireJiraCredentials(
|
|
18
19
|
event: Parameters<typeof requireCredential>[0],
|
|
19
20
|
) {
|
|
21
|
+
const workspaceConnection = await resolveWorkspaceConnectionForApp({
|
|
22
|
+
appId: "analytics",
|
|
23
|
+
provider: "jira",
|
|
24
|
+
requireConnected: true,
|
|
25
|
+
});
|
|
26
|
+
if (workspaceConnection.available) return null;
|
|
20
27
|
return (
|
|
21
28
|
(await requireCredential(event, "JIRA_BASE_URL", "Jira")) ||
|
|
22
29
|
(await requireCredential(event, "JIRA_USER_EMAIL", "Jira")) ||
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
// Jira Cloud REST API client
|
|
2
|
-
// Uses Basic auth (email + API token)
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
requireRequestCredentialContext,
|
|
7
|
-
scopedCredentialCacheKey,
|
|
8
|
-
} from "./credentials-context";
|
|
3
|
+
import { scopedCredentialCacheKey } from "./credentials-context";
|
|
4
|
+
import { executeProviderApiRequest } from "./provider-api";
|
|
9
5
|
|
|
10
6
|
const API_V3 = "/rest/api/3";
|
|
11
7
|
const API_AGILE = "/rest/agile/1.0";
|
|
@@ -15,29 +11,6 @@ const cache = new Map<string, { data: unknown; ts: number }>();
|
|
|
15
11
|
const CACHE_TTL_MS = 10 * 60 * 1000;
|
|
16
12
|
const MAX_CACHE = 100;
|
|
17
13
|
|
|
18
|
-
async function getAuth(): Promise<{
|
|
19
|
-
baseUrl: string;
|
|
20
|
-
headers: Record<string, string>;
|
|
21
|
-
}> {
|
|
22
|
-
const ctx = requireRequestCredentialContext("JIRA_BASE_URL");
|
|
23
|
-
const baseUrl = await resolveCredential("JIRA_BASE_URL", ctx);
|
|
24
|
-
const email = await resolveCredential("JIRA_USER_EMAIL", ctx);
|
|
25
|
-
const token = await resolveCredential("JIRA_API_TOKEN", ctx);
|
|
26
|
-
if (!baseUrl || !email || !token) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
"JIRA_BASE_URL, JIRA_USER_EMAIL, and JIRA_API_TOKEN are not configured",
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
const encoded = Buffer.from(`${email}:${token}`).toString("base64");
|
|
32
|
-
return {
|
|
33
|
-
baseUrl: baseUrl.replace(/\/$/, ""),
|
|
34
|
-
headers: {
|
|
35
|
-
Authorization: `Basic ${encoded}`,
|
|
36
|
-
Accept: "application/json",
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
14
|
async function jiraGet<T>(
|
|
42
15
|
path: string,
|
|
43
16
|
params?: Record<string, string>,
|
|
@@ -53,21 +26,20 @@ async function jiraGet<T>(
|
|
|
53
26
|
return cached.data as T;
|
|
54
27
|
}
|
|
55
28
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
throw new Error(`Jira API error ${res.status}: ${text}`);
|
|
29
|
+
const result = (await executeProviderApiRequest({
|
|
30
|
+
provider: "jira",
|
|
31
|
+
path,
|
|
32
|
+
query: params,
|
|
33
|
+
})) as {
|
|
34
|
+
response: { ok: boolean; status: number; json?: unknown; text?: string };
|
|
35
|
+
};
|
|
36
|
+
if (!result.response.ok) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Jira API error ${result.response.status}: ${String(result.response.text ?? "")}`,
|
|
39
|
+
);
|
|
68
40
|
}
|
|
69
41
|
|
|
70
|
-
const data =
|
|
42
|
+
const data = result.response.json;
|
|
71
43
|
if (cache.size >= MAX_CACHE) {
|
|
72
44
|
const oldest = cache.keys().next().value;
|
|
73
45
|
if (oldest) cache.delete(oldest);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readBody } from "@agent-native/core/server";
|
|
2
|
+
import { resolveWorkspaceConnectionForApp } from "@agent-native/core/workspace-connections";
|
|
2
3
|
import { defineEventHandler } from "h3";
|
|
3
4
|
|
|
4
5
|
import {
|
|
@@ -141,6 +142,16 @@ export default defineEventHandler(async (event) => {
|
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
case "jira": {
|
|
145
|
+
const workspaceConnection = await resolveWorkspaceConnectionForApp({
|
|
146
|
+
appId: "analytics",
|
|
147
|
+
provider: "jira",
|
|
148
|
+
requireConnected: true,
|
|
149
|
+
});
|
|
150
|
+
if (workspaceConnection.available) {
|
|
151
|
+
const { getProjects } = await import("../../lib/jira");
|
|
152
|
+
await getProjects();
|
|
153
|
+
return { ok: true };
|
|
154
|
+
}
|
|
144
155
|
const baseUrl = await resolveCredential("JIRA_BASE_URL", ctx);
|
|
145
156
|
const email = await resolveCredential("JIRA_USER_EMAIL", ctx);
|
|
146
157
|
const token = await resolveCredential("JIRA_API_TOKEN", ctx);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type RouteConfig } from "@react-router/dev/routes";
|
|
2
2
|
import { flatRoutes } from "@react-router/fs-routes";
|
|
3
3
|
|
|
4
|
-
export default flatRoutes(
|
|
4
|
+
export default flatRoutes({
|
|
5
|
+
ignoredRouteFiles: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
|
|
6
|
+
}) satisfies RouteConfig;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
agentNativePath,
|
|
2
3
|
useActionMutation,
|
|
3
4
|
useActionQuery,
|
|
4
5
|
useT,
|
|
@@ -127,6 +128,13 @@ interface WorkspaceConnectionProvider {
|
|
|
127
128
|
credentialKeys: WorkspaceConnectionCredentialKey[];
|
|
128
129
|
capabilities: string[];
|
|
129
130
|
recommendedTemplateUses: string[];
|
|
131
|
+
oauth?: {
|
|
132
|
+
provider: string;
|
|
133
|
+
authorizationUrl: string;
|
|
134
|
+
tokenUrl: string;
|
|
135
|
+
refreshUrl?: string;
|
|
136
|
+
scopes: string[];
|
|
137
|
+
};
|
|
130
138
|
readiness?: WorkspaceConnectionProviderReadiness;
|
|
131
139
|
}
|
|
132
140
|
|
|
@@ -718,6 +726,32 @@ function summarizeAppList(
|
|
|
718
726
|
: t("integrations.noApps");
|
|
719
727
|
}
|
|
720
728
|
|
|
729
|
+
function startWorkspaceProviderOAuth(provider: WorkspaceConnectionProvider) {
|
|
730
|
+
const returnPath = `${window.location.pathname}${window.location.search}`;
|
|
731
|
+
if (provider.id === "slack") {
|
|
732
|
+
const params = new URLSearchParams({ return: returnPath });
|
|
733
|
+
window.location.assign(
|
|
734
|
+
agentNativePath(
|
|
735
|
+
`/_agent-native/integrations/slack/oauth/install?${params.toString()}`,
|
|
736
|
+
),
|
|
737
|
+
);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const params = new URLSearchParams({
|
|
741
|
+
appId: "dispatch",
|
|
742
|
+
return: returnPath,
|
|
743
|
+
});
|
|
744
|
+
window.location.assign(
|
|
745
|
+
agentNativePath(
|
|
746
|
+
`/_agent-native/connections/oauth/${provider.id}/start?${params.toString()}`,
|
|
747
|
+
),
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
function providerHasOAuth(provider: WorkspaceConnectionProvider): boolean {
|
|
752
|
+
return Boolean(provider.oauth) || provider.id === "slack";
|
|
753
|
+
}
|
|
754
|
+
|
|
721
755
|
function ProviderCard({
|
|
722
756
|
provider,
|
|
723
757
|
connections,
|
|
@@ -788,10 +822,29 @@ function ProviderCard({
|
|
|
788
822
|
count: provider.credentialKeys.length,
|
|
789
823
|
})}
|
|
790
824
|
</span>
|
|
791
|
-
<
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
825
|
+
<div className="flex items-center gap-2">
|
|
826
|
+
{providerHasOAuth(provider) ? (
|
|
827
|
+
<Button
|
|
828
|
+
type="button"
|
|
829
|
+
size="sm"
|
|
830
|
+
onClick={() => startWorkspaceProviderOAuth(provider)}
|
|
831
|
+
>
|
|
832
|
+
<IconShieldCheck size={14} />
|
|
833
|
+
{t("integrations.connect")}
|
|
834
|
+
</Button>
|
|
835
|
+
) : null}
|
|
836
|
+
<Button
|
|
837
|
+
type="button"
|
|
838
|
+
variant={providerHasOAuth(provider) ? "ghost" : "outline"}
|
|
839
|
+
size="sm"
|
|
840
|
+
onClick={onCreate}
|
|
841
|
+
>
|
|
842
|
+
<IconKey size={14} />
|
|
843
|
+
{providerHasOAuth(provider)
|
|
844
|
+
? t("integrations.connectionFallback")
|
|
845
|
+
: t("integrations.connect")}
|
|
846
|
+
</Button>
|
|
847
|
+
</div>
|
|
795
848
|
</div>
|
|
796
849
|
</article>
|
|
797
850
|
);
|
|
@@ -212,7 +212,7 @@ export function shouldShowAgentPanelChatTabBar(tabs, activeTabId) {
|
|
|
212
212
|
return mainTabs.length > 1 || hasSubTabs;
|
|
213
213
|
}
|
|
214
214
|
export function shouldShowAgentPanelSidebarChatTabs(tabs) {
|
|
215
|
-
return tabs.
|
|
215
|
+
return tabs.filter((tab) => !tab.parentThreadId).length > 1;
|
|
216
216
|
}
|
|
217
217
|
export function shouldShowAgentPanelPageNewChatButton(tabs, activeTabId, activeTabMessageCount) {
|
|
218
218
|
if (!activeTabId)
|