@promptbook/cli 0.112.0-134 → 0.112.0-136
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/apps/agents-server/README.md +0 -1
- package/apps/agents-server/src/app/admin/chat-feedback/page.tsx +2 -4
- package/apps/agents-server/src/app/admin/chat-history/page.tsx +2 -4
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +246 -15
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +237 -4
- package/apps/agents-server/src/app/api/admin/update/log/route.ts +42 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +28 -9
- package/apps/agents-server/src/app/api/agents/export/route.ts +41 -0
- package/apps/agents-server/src/app/api/agents/import/route.ts +168 -0
- package/apps/agents-server/src/app/api/chat/route.ts +29 -7
- package/apps/agents-server/src/app/api/chat-feedback/export/route.ts +2 -2
- package/apps/agents-server/src/app/api/chat-feedback/route.ts +3 -3
- package/apps/agents-server/src/app/api/chat-history/[id]/route.ts +2 -2
- package/apps/agents-server/src/app/api/chat-history/export/route.ts +2 -2
- package/apps/agents-server/src/app/api/chat-history/route.ts +3 -3
- package/apps/agents-server/src/app/api/chat-streaming/route.ts +29 -0
- package/apps/agents-server/src/app/api/elevenlabs/tts/route.ts +60 -2
- package/apps/agents-server/src/app/api/federated-agents/route.ts +1 -1
- package/apps/agents-server/src/app/api/images/[filename]/route.ts +102 -0
- package/apps/agents-server/src/app/api/metadata/export/route.ts +34 -0
- package/apps/agents-server/src/app/api/metadata/import/route.ts +46 -0
- package/apps/agents-server/src/app/api/openai/v1/audio/transcriptions/route.ts +111 -2
- package/apps/agents-server/src/app/api/page-preview/check/route.ts +18 -0
- package/apps/agents-server/src/app/api/page-preview/screenshot/route.ts +15 -8
- package/apps/agents-server/src/app/api/team-agent-profile/route.ts +20 -0
- package/apps/agents-server/src/app/layout.tsx +1 -1
- package/apps/agents-server/src/components/AgentContextMenu/useAgentContextMenuItems.ts +27 -19
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +31 -1
- package/apps/agents-server/src/components/Homepage/AgentsListHeader.tsx +60 -1
- package/apps/agents-server/src/components/Homepage/useAgentsListImportExportState.ts +523 -0
- package/apps/agents-server/src/components/Homepage/useAgentsListState.ts +16 -0
- package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
- package/apps/agents-server/src/database/metadataDefaults.ts +0 -21
- package/apps/agents-server/src/database/migrations/2026-06-2700-default-agent-avatar-visual-octopus3d4.sql +16 -0
- package/apps/agents-server/src/database/seedCoreAgents.ts +235 -0
- package/apps/agents-server/src/database/seedDefaultAgents.ts +32 -1
- package/apps/agents-server/src/search/createDefaultServerSearchProviders/createFederatedAgentsSearchProvider.ts +1 -1
- package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +2 -9
- package/apps/agents-server/src/utils/agentOwnership.ts +54 -5
- package/apps/agents-server/src/utils/agentsTransfer/createAgentsExportZipStream.ts +68 -0
- package/apps/agents-server/src/utils/agentsTransfer/importAgentsFromFiles.ts +852 -0
- package/apps/agents-server/src/utils/backup/createBooksBackupZipStream.ts +15 -2
- package/apps/agents-server/src/utils/defaultAgents/loadDefaultAgentBooks.ts +46 -4
- package/apps/agents-server/src/utils/findAgentForCallerWriteAccess.ts +36 -0
- package/apps/agents-server/src/utils/getFederatedServers.ts +3 -74
- package/apps/agents-server/src/utils/getWellKnownAgentUrl.ts +10 -4
- package/apps/agents-server/src/utils/metadataConfigurationTransfer.ts +426 -0
- package/apps/agents-server/src/utils/paidApiRequestGuard.ts +241 -0
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/bootstrapManagedServer.ts +2 -5
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerCoreAgents.ts +162 -0
- package/apps/agents-server/src/utils/userChat/createRunUserChatJobExecutionContext.ts +36 -8
- package/apps/agents-server/src/utils/userChat/persistUserChatJobProgressCard.ts +11 -2
- package/apps/agents-server/src/utils/userChat/resolveUserChatProgressToolHighlights.ts +100 -0
- package/apps/agents-server/src/utils/userChat/runUserChatJob.ts +4 -3
- package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +272 -27
- package/apps/agents-server/src/utils/validateApiKey.ts +7 -3
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +110 -0
- package/esm/index.es.js +795 -39
- package/esm/index.es.js.map +1 -1
- package/esm/src/_packages/core.index.d.ts +0 -2
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/octopus3d4AvatarVisual.d.ts +7 -0
- package/esm/src/utils/validators/url/isValidAgentUrl.d.ts +5 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/servers.ts +1 -16
- package/src/_packages/core.index.ts +0 -2
- package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
- package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
- package/src/avatars/visuals/octopus3d4AvatarVisual.ts +1295 -0
- package/src/other/templates/getTemplatesPipelineCollection.ts +762 -883
- package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
- package/src/utils/validators/url/isValidAgentUrl.ts +5 -7
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -1
- package/umd/index.umd.js +795 -39
- package/umd/index.umd.js.map +1 -1
- package/umd/src/_packages/core.index.d.ts +0 -2
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/octopus3d4AvatarVisual.d.ts +7 -0
- package/umd/src/utils/validators/url/isValidAgentUrl.d.ts +5 -0
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/utils/defaultFederatedAgents/DefaultFederatedAgentsSyncOptions.ts +0 -9
- package/apps/agents-server/src/utils/defaultFederatedAgents/ensureDefaultFederatedAgentExists.ts +0 -277
- package/apps/agents-server/src/utils/defaultFederatedAgents/fetchCoreOrganizationPayload.ts +0 -39
- package/apps/agents-server/src/utils/defaultFederatedAgents/fetchFederatedAgentBook.ts +0 -43
- package/apps/agents-server/src/utils/defaultFederatedAgents/fetchWithDefaultFederatedAgentTimeout.ts +0 -28
- package/apps/agents-server/src/utils/defaultFederatedAgents/getDefaultFederatedAgentSyncPool.ts +0 -38
- package/apps/agents-server/src/utils/defaultFederatedAgents/loadActiveLocalAgentIdsByNormalizedName.ts +0 -41
- package/apps/agents-server/src/utils/defaultFederatedAgents/loadDefaultFederatedAgentSyncMetadata.ts +0 -76
- package/apps/agents-server/src/utils/defaultFederatedAgents/quoteIdentifier.ts +0 -11
- package/apps/agents-server/src/utils/defaultFederatedAgents/scheduleDefaultFederatedAgentsSync.ts +0 -88
- package/apps/agents-server/src/utils/defaultFederatedAgents/selectDefaultFederatedAgentsFromOrganizationPayload.ts +0 -181
- package/apps/agents-server/src/utils/defaultFederatedAgents/synchronizeDefaultFederatedAgents.ts +0 -77
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { NextRequest } from 'next/server';
|
|
2
2
|
import { NextResponse } from 'next/server';
|
|
3
3
|
import { assertsError } from '../../../../../../../src/errors/assertsError';
|
|
4
|
+
import { assertSafeUrl } from '../../../../utils/assertSafeUrl';
|
|
5
|
+
import { getCurrentUser } from '../../../../utils/getCurrentUser';
|
|
4
6
|
import { checkIfUrlCanBeEmbedded } from '../../../../utils/iframe/checkIfUrlCanBeEmbedded';
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -11,14 +13,30 @@ import { checkIfUrlCanBeEmbedded } from '../../../../utils/iframe/checkIfUrlCanB
|
|
|
11
13
|
* - `url` — the fully-qualified HTTP(S) URL to check
|
|
12
14
|
*
|
|
13
15
|
* Returns `{ canEmbed: boolean }`.
|
|
16
|
+
*
|
|
17
|
+
* Requires authentication to prevent unauthenticated SSRF abuse.
|
|
18
|
+
* The destination URL is validated against private/internal IP ranges before fetching.
|
|
14
19
|
*/
|
|
15
20
|
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
21
|
+
const currentUser = await getCurrentUser();
|
|
22
|
+
if (!currentUser) {
|
|
23
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
const url = request.nextUrl.searchParams.get('url');
|
|
17
27
|
|
|
18
28
|
if (!url) {
|
|
19
29
|
return NextResponse.json({ error: 'Missing required query parameter: url' }, { status: 400 });
|
|
20
30
|
}
|
|
21
31
|
|
|
32
|
+
// Guard against SSRF: reject private/internal IPs and non-HTTP(S) schemes
|
|
33
|
+
try {
|
|
34
|
+
assertSafeUrl(url);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
assertsError(error);
|
|
37
|
+
return NextResponse.json({ error: error.message }, { status: 400 });
|
|
38
|
+
}
|
|
39
|
+
|
|
22
40
|
try {
|
|
23
41
|
const canEmbed = await checkIfUrlCanBeEmbedded(url);
|
|
24
42
|
return NextResponse.json({ canEmbed });
|
|
@@ -3,6 +3,8 @@ import { serializeError } from '@promptbook-local/utils';
|
|
|
3
3
|
import type { NextRequest } from 'next/server';
|
|
4
4
|
import { NextResponse } from 'next/server';
|
|
5
5
|
import { assertsError } from '../../../../../../../src/errors/assertsError';
|
|
6
|
+
import { assertSafeUrl } from '../../../../utils/assertSafeUrl';
|
|
7
|
+
import { getCurrentUser } from '../../../../utils/getCurrentUser';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Takes a screenshot of the given URL using a headless browser.
|
|
@@ -11,23 +13,28 @@ import { assertsError } from '../../../../../../../src/errors/assertsError';
|
|
|
11
13
|
* - `url` — the fully-qualified HTTP(S) URL to screenshot
|
|
12
14
|
*
|
|
13
15
|
* Returns a PNG image.
|
|
16
|
+
*
|
|
17
|
+
* Requires authentication to prevent unauthenticated SSRF abuse.
|
|
18
|
+
* The destination URL is validated against private/internal IP ranges before fetching.
|
|
14
19
|
*/
|
|
15
20
|
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
21
|
+
const currentUser = await getCurrentUser();
|
|
22
|
+
if (!currentUser) {
|
|
23
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
const url = request.nextUrl.searchParams.get('url');
|
|
17
27
|
|
|
18
28
|
if (!url) {
|
|
19
29
|
return NextResponse.json({ error: 'Missing required query parameter: url' }, { status: 400 });
|
|
20
30
|
}
|
|
21
31
|
|
|
22
|
-
|
|
32
|
+
// Guard against SSRF: reject private/internal IPs and non-HTTP(S) schemes
|
|
23
33
|
try {
|
|
24
|
-
|
|
25
|
-
} catch {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
|
30
|
-
return NextResponse.json({ error: 'Only http and https URLs are supported' }, { status: 400 });
|
|
34
|
+
assertSafeUrl(url);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
assertsError(error);
|
|
37
|
+
return NextResponse.json({ error: error.message }, { status: 400 });
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
try {
|
|
@@ -8,7 +8,10 @@ import {
|
|
|
8
8
|
resolvePlaceholderImageUrl,
|
|
9
9
|
resolveProfileImageUrl,
|
|
10
10
|
} from '../../../../../../src/book-components/Chat/utils/loadAgentProfile';
|
|
11
|
+
import { assertsError } from '../../../../../../src/errors/assertsError';
|
|
11
12
|
import { isValidAgentUrl } from '../../../../../../src/utils/validators/url/isValidAgentUrl';
|
|
13
|
+
import { assertSafeUrl } from '../../../utils/assertSafeUrl';
|
|
14
|
+
import { getCurrentUser } from '../../../utils/getCurrentUser';
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* Response for team agent profile.
|
|
@@ -88,8 +91,17 @@ async function fetchAgentProfile(agentUrl: string, localServerUrl: string): Prom
|
|
|
88
91
|
*
|
|
89
92
|
* The client uses this to render tool call chips without relying on direct cross-origin requests
|
|
90
93
|
* to the teammate agent.
|
|
94
|
+
*
|
|
95
|
+
* Requires authentication to prevent unauthenticated SSRF abuse and exfiltration of the
|
|
96
|
+
* internal team access token. The destination URL is validated against private/internal
|
|
97
|
+
* IP ranges before any outbound request is made.
|
|
91
98
|
*/
|
|
92
99
|
export async function GET(request: Request) {
|
|
100
|
+
const currentUser = await getCurrentUser();
|
|
101
|
+
if (!currentUser) {
|
|
102
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
const requestUrl = new URL(request.url);
|
|
94
106
|
const agentUrl = requestUrl.searchParams.get('url');
|
|
95
107
|
|
|
@@ -97,6 +109,14 @@ export async function GET(request: Request) {
|
|
|
97
109
|
return NextResponse.json({ error: 'Invalid agent URL' }, { status: 400 });
|
|
98
110
|
}
|
|
99
111
|
|
|
112
|
+
// Guard against SSRF: reject private/internal IPs and non-HTTP(S) schemes
|
|
113
|
+
try {
|
|
114
|
+
assertSafeUrl(agentUrl);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
assertsError(error);
|
|
117
|
+
return NextResponse.json({ error: error.message }, { status: 400 });
|
|
118
|
+
}
|
|
119
|
+
|
|
100
120
|
const normalizedUrl = agentUrl.replace(/\/$/, '');
|
|
101
121
|
const profile = await fetchAgentProfile(normalizedUrl, requestUrl.origin);
|
|
102
122
|
|
|
@@ -149,7 +149,7 @@ async function getLayoutFederatedServers(options: {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
try {
|
|
152
|
-
const federatedServerUrls = await getFederatedServers(
|
|
152
|
+
const federatedServerUrls = await getFederatedServers();
|
|
153
153
|
return Promise.all(
|
|
154
154
|
federatedServerUrls.map(async (url) => ({
|
|
155
155
|
title: `Federated: ${new URL(url).hostname}`,
|
|
@@ -300,6 +300,7 @@ function createManagementMenuItems(
|
|
|
300
300
|
* @param formatText - Agent-aware text formatter.
|
|
301
301
|
* @param handleRequestVisibilityUpdate - Visibility dialog action.
|
|
302
302
|
* @param integrationLink - Generated integration link metadata.
|
|
303
|
+
* @param isAdmin - Whether the current user is an administrator (gates admin-only links).
|
|
303
304
|
* @param isAuthenticated - Whether the current user is logged in.
|
|
304
305
|
* @param shouldShowVisibilityAction - Whether visibility editing is available.
|
|
305
306
|
* @param usageAnalyticsHref - Usage analytics URL for the current agent.
|
|
@@ -311,6 +312,7 @@ function createAdminMenuItems(
|
|
|
311
312
|
formatText: FormatAgentContextMenuText,
|
|
312
313
|
handleRequestVisibilityUpdate: () => Promise<void>,
|
|
313
314
|
integrationLink: AgentContextMenuNavigationLink,
|
|
315
|
+
isAdmin: boolean,
|
|
314
316
|
isAuthenticated: boolean,
|
|
315
317
|
shouldShowVisibilityAction: boolean,
|
|
316
318
|
usageAnalyticsHref: string,
|
|
@@ -333,26 +335,31 @@ function createAdminMenuItems(
|
|
|
333
335
|
);
|
|
334
336
|
}
|
|
335
337
|
|
|
338
|
+
if (isAdmin) {
|
|
339
|
+
menuItems.push(
|
|
340
|
+
{
|
|
341
|
+
type: 'link',
|
|
342
|
+
href: `/admin/chat-history?agentName=${encodeURIComponent(agentName)}`,
|
|
343
|
+
icon: MessageSquareIcon,
|
|
344
|
+
label: formatText('Chat History'),
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
type: 'link',
|
|
348
|
+
href: usageAnalyticsHref,
|
|
349
|
+
icon: BarChart3Icon,
|
|
350
|
+
label: formatText('Usage Analytics'),
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
type: 'link',
|
|
354
|
+
href: `/admin/chat-feedback?agentName=${encodeURIComponent(agentName)}`,
|
|
355
|
+
icon: MessageCircleQuestionIcon,
|
|
356
|
+
label: formatText('Chat Feedback'),
|
|
357
|
+
},
|
|
358
|
+
createDividerItem(),
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
336
362
|
menuItems.push(
|
|
337
|
-
{
|
|
338
|
-
type: 'link',
|
|
339
|
-
href: `/admin/chat-history?agentName=${encodeURIComponent(agentName)}`,
|
|
340
|
-
icon: MessageSquareIcon,
|
|
341
|
-
label: formatText('Chat History'),
|
|
342
|
-
},
|
|
343
|
-
{
|
|
344
|
-
type: 'link',
|
|
345
|
-
href: usageAnalyticsHref,
|
|
346
|
-
icon: BarChart3Icon,
|
|
347
|
-
label: formatText('Usage Analytics'),
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
type: 'link',
|
|
351
|
-
href: `/admin/chat-feedback?agentName=${encodeURIComponent(agentName)}`,
|
|
352
|
-
icon: MessageCircleQuestionIcon,
|
|
353
|
-
label: formatText('Chat Feedback'),
|
|
354
|
-
},
|
|
355
|
-
createDividerItem(),
|
|
356
363
|
{
|
|
357
364
|
type: 'link',
|
|
358
365
|
href: integrationLink.href,
|
|
@@ -437,6 +444,7 @@ export function useAgentContextMenuItems(props: AgentContextMenuBaseProps): Cont
|
|
|
437
444
|
formatText,
|
|
438
445
|
handleRequestVisibilityUpdate,
|
|
439
446
|
integrationLink,
|
|
447
|
+
isAdmin,
|
|
440
448
|
isAuthenticated,
|
|
441
449
|
shouldShowVisibilityAction,
|
|
442
450
|
usageAnalyticsHref,
|
|
@@ -6,6 +6,7 @@ import type { AgentOrganizationAgent, AgentOrganizationFolder } from '../../util
|
|
|
6
6
|
import { AgentsListDialogs } from './AgentsListDialogs';
|
|
7
7
|
import { AgentsListHeader } from './AgentsListHeader';
|
|
8
8
|
import { AgentsListViewContent } from './AgentsListViewContent';
|
|
9
|
+
import { AGENTS_IMPORT_FILE_INPUT_ACCEPT } from './useAgentsListImportExportState';
|
|
9
10
|
import type { AgentWithVisibility } from './useFederatedAgents';
|
|
10
11
|
import { useAgentsListState } from './useAgentsListState';
|
|
11
12
|
|
|
@@ -72,14 +73,43 @@ export function AgentsList(props: AgentsListProps) {
|
|
|
72
73
|
isAdmin && contextMenuFolder ? () => state.handleRequestFolderVisibilityUpdate(contextMenuFolder.id) : undefined;
|
|
73
74
|
|
|
74
75
|
return (
|
|
75
|
-
<section
|
|
76
|
+
<section
|
|
77
|
+
className={`relative mt-16 first:mt-4 mb-4 ${
|
|
78
|
+
state.isAgentsImportDragActive ? 'rounded-xl ring-2 ring-blue-400 ring-offset-4' : ''
|
|
79
|
+
}`}
|
|
80
|
+
onDragEnter={isAdmin ? state.handleAgentsFileDragEnter : undefined}
|
|
81
|
+
onDragLeave={isAdmin ? state.handleAgentsFileDragLeave : undefined}
|
|
82
|
+
onDragOver={isAdmin ? state.handleAgentsFileDragOver : undefined}
|
|
83
|
+
onDrop={isAdmin ? state.handleAgentsFileDrop : undefined}
|
|
84
|
+
>
|
|
85
|
+
{isAdmin && (
|
|
86
|
+
<input
|
|
87
|
+
ref={state.importFileInputRef}
|
|
88
|
+
type="file"
|
|
89
|
+
multiple
|
|
90
|
+
accept={AGENTS_IMPORT_FILE_INPUT_ACCEPT}
|
|
91
|
+
className="hidden"
|
|
92
|
+
onChange={(event) => void state.handleAgentsImportFileChange(event)}
|
|
93
|
+
disabled={state.isAgentsImporting}
|
|
94
|
+
/>
|
|
95
|
+
)}
|
|
96
|
+
{isAdmin && state.isAgentsImportDragActive && (
|
|
97
|
+
<div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center rounded-xl border-2 border-dashed border-blue-400 bg-blue-50/85 text-sm font-medium text-blue-800 shadow-sm">
|
|
98
|
+
Drop books or ZIP archives to import agents
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
76
101
|
<AgentsListHeader
|
|
77
102
|
agentCount={state.agentCount}
|
|
78
103
|
allAgentsLabel={state.allAgentsLabel}
|
|
79
104
|
breadcrumbFolders={state.breadcrumbFolders}
|
|
80
105
|
canOrganize={canOrganize}
|
|
81
106
|
headingTitle={state.headingTitle}
|
|
107
|
+
isAdmin={isAdmin}
|
|
108
|
+
isAgentsExporting={state.isAgentsExporting}
|
|
109
|
+
isAgentsImporting={state.isAgentsImporting}
|
|
82
110
|
onCreateFolder={state.handleCreateFolder}
|
|
111
|
+
onExportAgents={() => void state.handleAgentsExport()}
|
|
112
|
+
onImportAgents={state.handleAgentsImportClick}
|
|
83
113
|
onNavigateToFolder={state.navigateToFolder}
|
|
84
114
|
onSetViewMode={state.setViewMode}
|
|
85
115
|
viewMode={state.viewMode}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Building2,
|
|
5
|
+
DownloadIcon,
|
|
6
|
+
FolderPlusIcon,
|
|
7
|
+
Gamepad2,
|
|
8
|
+
Grid,
|
|
9
|
+
Map,
|
|
10
|
+
Network,
|
|
11
|
+
UploadIcon,
|
|
12
|
+
type LucideIcon,
|
|
13
|
+
} from 'lucide-react';
|
|
4
14
|
import type { AgentOrganizationFolder } from '../../utils/agentOrganization/types';
|
|
5
15
|
import type { HomeViewMode } from './homeViewMode';
|
|
6
16
|
import { BreadcrumbDropTarget } from './BreadcrumbDropTarget';
|
|
@@ -55,6 +65,18 @@ type AgentsListHeaderProps = {
|
|
|
55
65
|
* Current heading title.
|
|
56
66
|
*/
|
|
57
67
|
readonly headingTitle: string;
|
|
68
|
+
/**
|
|
69
|
+
* Whether agents import/export controls are available.
|
|
70
|
+
*/
|
|
71
|
+
readonly isAdmin: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Downloads an agents export.
|
|
74
|
+
*/
|
|
75
|
+
readonly onExportAgents: () => void;
|
|
76
|
+
/**
|
|
77
|
+
* Opens the agents import file picker.
|
|
78
|
+
*/
|
|
79
|
+
readonly onImportAgents: () => void;
|
|
58
80
|
/**
|
|
59
81
|
* Opens the create-folder dialog.
|
|
60
82
|
*/
|
|
@@ -71,6 +93,14 @@ type AgentsListHeaderProps = {
|
|
|
71
93
|
* Currently active homepage view mode.
|
|
72
94
|
*/
|
|
73
95
|
readonly viewMode: HomeViewMode;
|
|
96
|
+
/**
|
|
97
|
+
* Whether agents export is currently running.
|
|
98
|
+
*/
|
|
99
|
+
readonly isAgentsExporting: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Whether agents import is currently running.
|
|
102
|
+
*/
|
|
103
|
+
readonly isAgentsImporting: boolean;
|
|
74
104
|
};
|
|
75
105
|
|
|
76
106
|
/**
|
|
@@ -100,7 +130,12 @@ export function AgentsListHeader({
|
|
|
100
130
|
breadcrumbFolders,
|
|
101
131
|
canOrganize,
|
|
102
132
|
headingTitle,
|
|
133
|
+
isAdmin,
|
|
134
|
+
isAgentsExporting,
|
|
135
|
+
isAgentsImporting,
|
|
103
136
|
onCreateFolder,
|
|
137
|
+
onExportAgents,
|
|
138
|
+
onImportAgents,
|
|
104
139
|
onNavigateToFolder,
|
|
105
140
|
onSetViewMode,
|
|
106
141
|
viewMode,
|
|
@@ -138,6 +173,30 @@ export function AgentsListHeader({
|
|
|
138
173
|
)}
|
|
139
174
|
</div>
|
|
140
175
|
<div className="flex items-center gap-2">
|
|
176
|
+
{isListView && isAdmin && (
|
|
177
|
+
<>
|
|
178
|
+
<button
|
|
179
|
+
type="button"
|
|
180
|
+
onClick={onExportAgents}
|
|
181
|
+
disabled={isAgentsExporting || isAgentsImporting}
|
|
182
|
+
className="flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition-colors text-sm disabled:cursor-not-allowed disabled:opacity-60"
|
|
183
|
+
title="Export agents"
|
|
184
|
+
>
|
|
185
|
+
<DownloadIcon className="w-4 h-4" />
|
|
186
|
+
{isAgentsExporting ? 'Exporting...' : 'Export'}
|
|
187
|
+
</button>
|
|
188
|
+
<button
|
|
189
|
+
type="button"
|
|
190
|
+
onClick={onImportAgents}
|
|
191
|
+
disabled={isAgentsExporting || isAgentsImporting}
|
|
192
|
+
className="flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition-colors text-sm disabled:cursor-not-allowed disabled:opacity-60"
|
|
193
|
+
title="Import agents"
|
|
194
|
+
>
|
|
195
|
+
<UploadIcon className="w-4 h-4" />
|
|
196
|
+
{isAgentsImporting ? 'Importing...' : 'Import'}
|
|
197
|
+
</button>
|
|
198
|
+
</>
|
|
199
|
+
)}
|
|
141
200
|
{isListView && canOrganize && (
|
|
142
201
|
<button
|
|
143
202
|
type="button"
|