@elizaos/client 1.5.5-alpha.10
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/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/assets/empty-module-CLMscLYw.js +1 -0
- package/dist/assets/main-BBZ_3lkn.css +5999 -0
- package/dist/assets/main-C5zNUkXH.js +7 -0
- package/dist/assets/main-Dz64ENQg.js +614 -0
- package/dist/assets/react-vendor-DM5m98rr.js +545 -0
- package/dist/assets/ui-vendor-BQCqNqg0.js +1 -0
- package/dist/elizaos-avatar.png +0 -0
- package/dist/elizaos-icon.png +0 -0
- package/dist/elizaos-logo-light.png +0 -0
- package/dist/elizaos.webp +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/images/agents/agent1.png +0 -0
- package/dist/images/agents/agent2.png +0 -0
- package/dist/images/agents/agent3.png +0 -0
- package/dist/images/agents/agent4.png +0 -0
- package/dist/images/agents/agent5.png +0 -0
- package/dist/index.html +14 -0
- package/index.html +24 -0
- package/package.json +159 -0
- package/postcss.config.js +3 -0
- package/public/elizaos-avatar.png +0 -0
- package/public/elizaos-icon.png +0 -0
- package/public/elizaos-logo-light.png +0 -0
- package/public/elizaos.webp +0 -0
- package/public/favicon.ico +0 -0
- package/public/images/agents/agent1.png +0 -0
- package/public/images/agents/agent2.png +0 -0
- package/public/images/agents/agent3.png +0 -0
- package/public/images/agents/agent4.png +0 -0
- package/public/images/agents/agent5.png +0 -0
- package/src/App.tsx +222 -0
- package/src/components/AgentDetailsPanel.tsx +147 -0
- package/src/components/ChatInputArea.tsx +196 -0
- package/src/components/ChatMessageListComponent.tsx +139 -0
- package/src/components/actionTool.tsx +186 -0
- package/src/components/add-agent-card.tsx +77 -0
- package/src/components/agent-action-viewer.tsx +816 -0
- package/src/components/agent-avatar-stack.tsx +121 -0
- package/src/components/agent-card.cy.tsx +259 -0
- package/src/components/agent-card.tsx +177 -0
- package/src/components/agent-creator.tsx +142 -0
- package/src/components/agent-log-viewer.tsx +645 -0
- package/src/components/agent-memory-edit-overlay.tsx +461 -0
- package/src/components/agent-memory-viewer.tsx +504 -0
- package/src/components/agent-settings.tsx +270 -0
- package/src/components/agent-sidebar.tsx +178 -0
- package/src/components/api-key-dialog.tsx +113 -0
- package/src/components/app-sidebar.tsx +685 -0
- package/src/components/array-input.tsx +116 -0
- package/src/components/audio-recorder.tsx +292 -0
- package/src/components/avatar-panel.tsx +141 -0
- package/src/components/character-form.tsx +1138 -0
- package/src/components/chat.tsx +1813 -0
- package/src/components/combobox.tsx +187 -0
- package/src/components/confirmation-dialog.tsx +59 -0
- package/src/components/connection-error-banner.tsx +101 -0
- package/src/components/connection-status.cy.tsx +73 -0
- package/src/components/connection-status.tsx +155 -0
- package/src/components/copy-button.tsx +35 -0
- package/src/components/delete-button.tsx +24 -0
- package/src/components/env-settings.tsx +261 -0
- package/src/components/group-card.tsx +160 -0
- package/src/components/group-panel.tsx +543 -0
- package/src/components/input-copy.tsx +21 -0
- package/src/components/logs-page.tsx +41 -0
- package/src/components/media-content.tsx +385 -0
- package/src/components/memory-graph.tsx +170 -0
- package/src/components/missing-secrets-dialog.tsx +72 -0
- package/src/components/onboarding-tour.tsx +247 -0
- package/src/components/page-title.tsx +8 -0
- package/src/components/plugins-panel.tsx +383 -0
- package/src/components/profile-card.tsx +66 -0
- package/src/components/profile-overlay.tsx +283 -0
- package/src/components/retry-button.tsx +28 -0
- package/src/components/secret-panel.tsx +1505 -0
- package/src/components/server-management.tsx +264 -0
- package/src/components/split-button.tsx +148 -0
- package/src/components/stop-agent-button.tsx +99 -0
- package/src/components/ui/alert-dialog.cy.tsx +333 -0
- package/src/components/ui/alert-dialog.tsx +115 -0
- package/src/components/ui/alert.tsx +49 -0
- package/src/components/ui/avatar.cy.tsx +180 -0
- package/src/components/ui/avatar.tsx +57 -0
- package/src/components/ui/badge.cy.tsx +146 -0
- package/src/components/ui/badge.tsx +43 -0
- package/src/components/ui/button.cy.tsx +177 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.cy.tsx +160 -0
- package/src/components/ui/card.tsx +73 -0
- package/src/components/ui/chat/animated-markdown.tsx +59 -0
- package/src/components/ui/chat/chat-bubble.tsx +178 -0
- package/src/components/ui/chat/chat-container.tsx +51 -0
- package/src/components/ui/chat/chat-input.cy.tsx +169 -0
- package/src/components/ui/chat/chat-input.tsx +47 -0
- package/src/components/ui/chat/chat-message-list.tsx +61 -0
- package/src/components/ui/chat/chat-tts-button.tsx +199 -0
- package/src/components/ui/chat/code-block.tsx +79 -0
- package/src/components/ui/chat/expandable-chat.tsx +131 -0
- package/src/components/ui/chat/hooks/useAutoScroll.ts +86 -0
- package/src/components/ui/chat/markdown.tsx +209 -0
- package/src/components/ui/chat/message-loading.tsx +48 -0
- package/src/components/ui/checkbox.cy.tsx +170 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.cy.tsx +283 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/command.cy.tsx +313 -0
- package/src/components/ui/command.tsx +143 -0
- package/src/components/ui/dialog.cy.tsx +279 -0
- package/src/components/ui/dialog.tsx +104 -0
- package/src/components/ui/dropdown-menu.cy.tsx +273 -0
- package/src/components/ui/dropdown-menu.tsx +281 -0
- package/src/components/ui/input.cy.tsx +82 -0
- package/src/components/ui/input.tsx +27 -0
- package/src/components/ui/label.cy.tsx +157 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/resizable.tsx +42 -0
- package/src/components/ui/scroll-area.cy.tsx +242 -0
- package/src/components/ui/scroll-area.tsx +46 -0
- package/src/components/ui/select.cy.tsx +277 -0
- package/src/components/ui/select.tsx +155 -0
- package/src/components/ui/separator.cy.tsx +145 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.cy.tsx +324 -0
- package/src/components/ui/sheet.tsx +119 -0
- package/src/components/ui/sidebar.tsx +734 -0
- package/src/components/ui/skeleton.cy.tsx +149 -0
- package/src/components/ui/skeleton.tsx +17 -0
- package/src/components/ui/split-button.cy.tsx +274 -0
- package/src/components/ui/split-button.tsx +112 -0
- package/src/components/ui/switch.tsx +28 -0
- package/src/components/ui/tabs.cy.tsx +271 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.cy.tsx +136 -0
- package/src/components/ui/textarea.tsx +26 -0
- package/src/components/ui/toast.cy.tsx +209 -0
- package/src/components/ui/toast.tsx +126 -0
- package/src/components/ui/toaster.tsx +29 -0
- package/src/components/ui/tooltip.cy.tsx +244 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/config/agent-templates.ts +349 -0
- package/src/config/voice-models.ts +181 -0
- package/src/constants.ts +23 -0
- package/src/context/AuthContext.tsx +44 -0
- package/src/context/ConnectionContext.tsx +194 -0
- package/src/entry.tsx +9 -0
- package/src/hooks/__tests__/use-agent-tab-state.test.ts +137 -0
- package/src/hooks/__tests__/use-agent-update.test.tsx +250 -0
- package/src/hooks/__tests__/use-character-convert.test.ts +102 -0
- package/src/hooks/__tests__/use-panel-width-state.test.ts +243 -0
- package/src/hooks/__tests__/use-sidebar-state.test.ts +117 -0
- package/src/hooks/use-agent-management.ts +130 -0
- package/src/hooks/use-agent-tab-state.ts +74 -0
- package/src/hooks/use-agent-update.ts +469 -0
- package/src/hooks/use-character-convert.ts +138 -0
- package/src/hooks/use-confirmation.ts +55 -0
- package/src/hooks/use-delete-agent.ts +123 -0
- package/src/hooks/use-dm-channels.ts +198 -0
- package/src/hooks/use-elevenlabs-voices.ts +83 -0
- package/src/hooks/use-file-upload.ts +224 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/use-onboarding.tsx +49 -0
- package/src/hooks/use-panel-width-state.ts +147 -0
- package/src/hooks/use-partial-update.ts +288 -0
- package/src/hooks/use-plugin-details.ts +462 -0
- package/src/hooks/use-plugins.ts +119 -0
- package/src/hooks/use-query-hooks.ts +1263 -0
- package/src/hooks/use-server-agents.ts +62 -0
- package/src/hooks/use-server-version.tsx +47 -0
- package/src/hooks/use-sidebar-state.ts +50 -0
- package/src/hooks/use-socket-chat.ts +264 -0
- package/src/hooks/use-toast.ts +260 -0
- package/src/hooks/use-version.tsx +64 -0
- package/src/index.css +146 -0
- package/src/lib/api-client-config.ts +53 -0
- package/src/lib/api-type-mappers.ts +196 -0
- package/src/lib/export-utils.ts +123 -0
- package/src/lib/logger.ts +19 -0
- package/src/lib/media-utils.ts +170 -0
- package/src/lib/pca.test.ts +17 -0
- package/src/lib/pca.ts +52 -0
- package/src/lib/socketio-manager.ts +664 -0
- package/src/lib/utils.ts +168 -0
- package/src/main.tsx +16 -0
- package/src/mocks/empty-module.ts +12 -0
- package/src/mocks/node-module.ts +57 -0
- package/src/polyfills.ts +37 -0
- package/src/routes/agent-detail.tsx +30 -0
- package/src/routes/agent-list.tsx +27 -0
- package/src/routes/agent-settings.tsx +48 -0
- package/src/routes/character-detail.tsx +52 -0
- package/src/routes/character-form.tsx +79 -0
- package/src/routes/character-list.tsx +38 -0
- package/src/routes/chat.tsx +128 -0
- package/src/routes/createAgent.tsx +13 -0
- package/src/routes/group-new.tsx +50 -0
- package/src/routes/group.tsx +29 -0
- package/src/routes/home.tsx +218 -0
- package/src/routes/not-found.tsx +71 -0
- package/src/test/setup.ts +154 -0
- package/src/types/crypto-browserify.d.ts +4 -0
- package/src/types/index.ts +13 -0
- package/src/types/rooms.ts +8 -0
- package/src/types.ts +84 -0
- package/src/vite-env.d.ts +40 -0
- package/tailwind.config.ts +90 -0
- package/tsconfig.json +10 -0
- package/vite.config.ts +102 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import clientLogger from '@/lib/logger';
|
|
4
|
+
|
|
5
|
+
// Registry configuration - same as in use-plugins.ts
|
|
6
|
+
const REGISTRY_ORG = 'elizaos-plugins';
|
|
7
|
+
const REGISTRY_REPO = 'registry';
|
|
8
|
+
const REGISTRY_URL = `https://raw.githubusercontent.com/${REGISTRY_ORG}/${REGISTRY_REPO}/refs/heads/main/generated-registry.json`;
|
|
9
|
+
|
|
10
|
+
// Define the structure of plugin secrets requirements
|
|
11
|
+
interface PluginSecret {
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
required: boolean;
|
|
15
|
+
example?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface PluginPackageJson {
|
|
19
|
+
name: string;
|
|
20
|
+
version: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
elizaos?: {
|
|
23
|
+
secrets?: PluginSecret[];
|
|
24
|
+
requiredSecrets?: string[]; // Legacy format - just array of secret names
|
|
25
|
+
};
|
|
26
|
+
agentConfig?: {
|
|
27
|
+
pluginType?: string;
|
|
28
|
+
pluginParameters?: Record<
|
|
29
|
+
string,
|
|
30
|
+
{
|
|
31
|
+
type: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
required: boolean;
|
|
34
|
+
sensitive?: boolean;
|
|
35
|
+
example?: string;
|
|
36
|
+
}
|
|
37
|
+
>;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface PluginDetails {
|
|
42
|
+
name: string;
|
|
43
|
+
requiredSecrets: PluginSecret[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Core plugins that are part of the monorepo and don't need external fetching
|
|
47
|
+
const CORE_PLUGINS = ['@elizaos/plugin-bootstrap', '@elizaos/plugin-sql'];
|
|
48
|
+
|
|
49
|
+
// Registry types (same as in use-plugins.ts)
|
|
50
|
+
interface GitVersionInfo {
|
|
51
|
+
version: string | null;
|
|
52
|
+
branch: string | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface PluginGitInfo {
|
|
56
|
+
repo: string;
|
|
57
|
+
v0: GitVersionInfo;
|
|
58
|
+
v1: GitVersionInfo;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface PluginNpmInfo {
|
|
62
|
+
repo: string;
|
|
63
|
+
v0: string | null;
|
|
64
|
+
v1: string | null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface PluginSupport {
|
|
68
|
+
v0: boolean;
|
|
69
|
+
v1: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface PluginInfo {
|
|
73
|
+
git: PluginGitInfo;
|
|
74
|
+
npm: PluginNpmInfo;
|
|
75
|
+
supports: PluginSupport;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface RegistryResponse {
|
|
79
|
+
lastUpdatedAt: string;
|
|
80
|
+
registry: Record<string, PluginInfo>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Fetch the plugin registry to get GitHub repo information
|
|
85
|
+
*/
|
|
86
|
+
async function fetchPluginRegistry(): Promise<RegistryResponse | null> {
|
|
87
|
+
try {
|
|
88
|
+
const response = await fetch(REGISTRY_URL);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
throw new Error(`Failed to fetch registry: ${response.status}`);
|
|
91
|
+
}
|
|
92
|
+
return await response.json();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
clientLogger.error('Failed to fetch plugin registry:', error);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Convert plugin name for registry lookup - handles both @elizaos and @elizaos-plugins formats
|
|
101
|
+
*/
|
|
102
|
+
function getRegistryPluginName(pluginName: string): string {
|
|
103
|
+
// If already in @elizaos-plugins format, return as is
|
|
104
|
+
if (pluginName.startsWith('@elizaos-plugins/')) {
|
|
105
|
+
return pluginName;
|
|
106
|
+
}
|
|
107
|
+
// Convert @elizaos to @elizaos-plugins format
|
|
108
|
+
return pluginName.replace('@elizaos/', '@elizaos-plugins/');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if a plugin is a core plugin that doesn't need external fetching
|
|
113
|
+
*/
|
|
114
|
+
function isCorePlugin(pluginName: string): boolean {
|
|
115
|
+
return CORE_PLUGINS.includes(pluginName);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get GitHub repo path from registry data
|
|
120
|
+
*/
|
|
121
|
+
function getGitHubRepoPath(
|
|
122
|
+
pluginName: string,
|
|
123
|
+
registryData: RegistryResponse | null
|
|
124
|
+
): string | null {
|
|
125
|
+
// Skip core plugins
|
|
126
|
+
if (isCorePlugin(pluginName)) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!registryData) {
|
|
131
|
+
clientLogger.warn(`No registry data available for ${pluginName}`);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Try both naming conventions
|
|
136
|
+
const registryName = getRegistryPluginName(pluginName);
|
|
137
|
+
const alternativeName = pluginName; // Try the original name as well
|
|
138
|
+
|
|
139
|
+
clientLogger.debug(
|
|
140
|
+
`Looking for ${pluginName} in registry as ${registryName} or ${alternativeName}`
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Try primary registry name first
|
|
144
|
+
let pluginInfo = registryData.registry[registryName];
|
|
145
|
+
|
|
146
|
+
// If not found, try the alternative name
|
|
147
|
+
if (!pluginInfo && registryName !== alternativeName) {
|
|
148
|
+
pluginInfo = registryData.registry[alternativeName];
|
|
149
|
+
if (pluginInfo) {
|
|
150
|
+
clientLogger.debug(`Found plugin under alternative name: ${alternativeName}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!pluginInfo?.git?.repo) {
|
|
155
|
+
clientLogger.warn(
|
|
156
|
+
`No GitHub repo found in registry for plugin: ${pluginName} (tried ${registryName} and ${alternativeName})`
|
|
157
|
+
);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
clientLogger.debug(`Found repo info for ${pluginName}: ${pluginInfo.git.repo}`);
|
|
162
|
+
|
|
163
|
+
// Get the appropriate branch/version
|
|
164
|
+
const gitInfo = pluginInfo.git.v1.branch ? pluginInfo.git.v1 : pluginInfo.git.v0;
|
|
165
|
+
const branch = gitInfo?.branch || 'main'; // Default to 'main' if no branch info
|
|
166
|
+
|
|
167
|
+
if (!gitInfo?.branch) {
|
|
168
|
+
clientLogger.warn(`No branch information found for plugin: ${pluginName}`);
|
|
169
|
+
// Don't return null here - we'll try default branches in fetchPluginPackageJson
|
|
170
|
+
} else {
|
|
171
|
+
clientLogger.debug(`Branch for ${pluginName}: ${branch}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Extract owner/repo from the git URL
|
|
175
|
+
let ownerRepo: string;
|
|
176
|
+
|
|
177
|
+
const repoMatch = pluginInfo.git.repo.match(/github\.com[:/]([^/]+\/[^/.]+)(\.git)?$/);
|
|
178
|
+
if (repoMatch) {
|
|
179
|
+
ownerRepo = repoMatch[1];
|
|
180
|
+
} else {
|
|
181
|
+
// Try to parse as a simple owner/repo format (e.g., "elizaos-plugins/plugin-google-genai")
|
|
182
|
+
const simpleMatch = pluginInfo.git.repo.match(/^([^/]+\/[^/.]+)$/);
|
|
183
|
+
if (simpleMatch) {
|
|
184
|
+
ownerRepo = simpleMatch[1];
|
|
185
|
+
} else {
|
|
186
|
+
clientLogger.warn(`Could not parse GitHub repo URL: ${pluginInfo.git.repo}`);
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
clientLogger.debug(`Parsed owner/repo for ${pluginName}: ${ownerRepo}`);
|
|
192
|
+
|
|
193
|
+
// Return a simple path without packages subdirectory
|
|
194
|
+
// fetchPluginPackageJson will try various combinations
|
|
195
|
+
const finalPath = `${ownerRepo}/${branch}`;
|
|
196
|
+
clientLogger.debug(`Initial path for ${pluginName}: ${finalPath}`);
|
|
197
|
+
|
|
198
|
+
return finalPath;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Fetches package.json for a single plugin from GitHub
|
|
203
|
+
*/
|
|
204
|
+
async function fetchPluginPackageJson(
|
|
205
|
+
pluginName: string,
|
|
206
|
+
repoPath: string | null
|
|
207
|
+
): Promise<PluginPackageJson | null> {
|
|
208
|
+
// Skip core plugins
|
|
209
|
+
if (isCorePlugin(pluginName)) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!repoPath) {
|
|
214
|
+
clientLogger.warn(`No repo path available for plugin: ${pluginName}`);
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
clientLogger.debug(
|
|
219
|
+
`Starting package.json fetch for ${pluginName} with initial path: ${repoPath}`
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// Extract the base repo path
|
|
223
|
+
const pathParts = repoPath.split('/');
|
|
224
|
+
const owner = pathParts[0];
|
|
225
|
+
const repo = pathParts[1];
|
|
226
|
+
const branch = pathParts[2] || 'main';
|
|
227
|
+
const packageName = pluginName.replace('@elizaos/', '');
|
|
228
|
+
|
|
229
|
+
clientLogger.debug(
|
|
230
|
+
`Extracted parts - owner: ${owner}, repo: ${repo}, branch: ${branch}, packageName: ${packageName}`
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Try multiple possible paths for package.json
|
|
234
|
+
// Prioritize root-level (standalone repos) over monorepo structure
|
|
235
|
+
const possiblePaths = [
|
|
236
|
+
// Try with the provided branch first at root level
|
|
237
|
+
`${owner}/${repo}/${branch}`,
|
|
238
|
+
// Try common branch names at root level
|
|
239
|
+
`${owner}/${repo}/main`,
|
|
240
|
+
`${owner}/${repo}/master`,
|
|
241
|
+
`${owner}/${repo}/1.x`,
|
|
242
|
+
`${owner}/${repo}/v1`,
|
|
243
|
+
`${owner}/${repo}/v2`,
|
|
244
|
+
// Only try packages subdirectory as a last resort for monorepo structure
|
|
245
|
+
`${owner}/${repo}/${branch}/packages/${packageName}`,
|
|
246
|
+
`${owner}/${repo}/main/packages/${packageName}`,
|
|
247
|
+
`${owner}/${repo}/master/packages/${packageName}`,
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
// Remove duplicates while preserving order
|
|
251
|
+
const uniquePaths = [...new Set(possiblePaths)];
|
|
252
|
+
|
|
253
|
+
clientLogger.debug(`Will try ${uniquePaths.length} unique paths for ${pluginName}:`, uniquePaths);
|
|
254
|
+
|
|
255
|
+
for (const path of uniquePaths) {
|
|
256
|
+
try {
|
|
257
|
+
const url = `https://raw.githubusercontent.com/${path}/package.json`;
|
|
258
|
+
clientLogger.debug(`Trying URL for ${pluginName}: ${url}`);
|
|
259
|
+
|
|
260
|
+
const response = await fetch(url);
|
|
261
|
+
|
|
262
|
+
if (response.ok) {
|
|
263
|
+
const packageJson: PluginPackageJson = await response.json();
|
|
264
|
+
clientLogger.debug(`✅ Found package.json for ${pluginName} at ${url}`);
|
|
265
|
+
return packageJson;
|
|
266
|
+
} else {
|
|
267
|
+
clientLogger.debug(`❌ Failed to fetch ${pluginName} from ${url}: HTTP ${response.status}`);
|
|
268
|
+
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
// Silently continue to next path
|
|
271
|
+
clientLogger.debug(
|
|
272
|
+
`❌ Error fetching ${pluginName} from ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// If we couldn't find package.json in any location, log a warning but don't throw
|
|
278
|
+
clientLogger.warn(
|
|
279
|
+
`Could not find package.json for ${pluginName} in any of the expected locations`
|
|
280
|
+
);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Extract required secrets from package.json
|
|
286
|
+
*/
|
|
287
|
+
function extractRequiredSecrets(
|
|
288
|
+
pluginName: string,
|
|
289
|
+
packageJson: PluginPackageJson | null
|
|
290
|
+
): PluginSecret[] {
|
|
291
|
+
// Core plugins don't have required secrets
|
|
292
|
+
if (isCorePlugin(pluginName)) {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!packageJson) {
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// First, try to get secrets from agentConfig.pluginParameters (new format)
|
|
301
|
+
if (packageJson?.agentConfig?.pluginParameters) {
|
|
302
|
+
const secrets: PluginSecret[] = [];
|
|
303
|
+
for (const [name, config] of Object.entries(packageJson.agentConfig.pluginParameters)) {
|
|
304
|
+
// Fix linter error: only check for boolean true since required is typed as boolean
|
|
305
|
+
if (config.required === true) {
|
|
306
|
+
secrets.push({
|
|
307
|
+
name,
|
|
308
|
+
description: config.description,
|
|
309
|
+
required: true,
|
|
310
|
+
example: config.example,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// If we found agentConfig.pluginParameters, return the results even if empty
|
|
315
|
+
// This means the plugin explicitly defined its parameters and we should respect that
|
|
316
|
+
return secrets;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Try to get secrets from elizaos.secrets
|
|
320
|
+
if (packageJson?.elizaos?.secrets) {
|
|
321
|
+
return packageJson.elizaos.secrets.filter((secret) => secret.required);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Legacy format - convert string array to PluginSecret array
|
|
325
|
+
if (packageJson?.elizaos?.requiredSecrets) {
|
|
326
|
+
return packageJson.elizaos.requiredSecrets.map((secretName) => ({
|
|
327
|
+
name: secretName,
|
|
328
|
+
required: true,
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// No fallback secrets - if we can't find explicit configuration, don't assume anything
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Hook to fetch plugin details including required secrets
|
|
338
|
+
*/
|
|
339
|
+
export function usePluginDetails(pluginNames: string[]) {
|
|
340
|
+
// Create a stable key for the query to prevent infinite loops
|
|
341
|
+
const stablePluginNames = useMemo(() => {
|
|
342
|
+
return [...pluginNames].sort().join(',');
|
|
343
|
+
}, [pluginNames]);
|
|
344
|
+
|
|
345
|
+
return useQuery({
|
|
346
|
+
queryKey: ['plugin-details', stablePluginNames],
|
|
347
|
+
queryFn: async () => {
|
|
348
|
+
clientLogger.debug('[usePluginDetails] Starting fetch for plugins:', pluginNames);
|
|
349
|
+
const details: PluginDetails[] = [];
|
|
350
|
+
|
|
351
|
+
// Separate core plugins from external plugins
|
|
352
|
+
const corePlugins = pluginNames.filter(isCorePlugin);
|
|
353
|
+
const externalPlugins = pluginNames.filter((name) => !isCorePlugin(name));
|
|
354
|
+
|
|
355
|
+
clientLogger.debug('[usePluginDetails] Core plugins:', corePlugins);
|
|
356
|
+
clientLogger.debug('[usePluginDetails] External plugins:', externalPlugins);
|
|
357
|
+
|
|
358
|
+
// Add core plugins with empty secrets
|
|
359
|
+
corePlugins.forEach((name) => {
|
|
360
|
+
details.push({
|
|
361
|
+
name,
|
|
362
|
+
requiredSecrets: [],
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Only fetch registry if we have external plugins
|
|
367
|
+
if (externalPlugins.length > 0) {
|
|
368
|
+
// Fetch the registry to get repo information
|
|
369
|
+
const registryData = await fetchPluginRegistry();
|
|
370
|
+
clientLogger.debug(
|
|
371
|
+
'[usePluginDetails] Registry data fetched:',
|
|
372
|
+
registryData ? 'success' : 'failed'
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
// Log available plugins in registry for debugging
|
|
376
|
+
if (registryData) {
|
|
377
|
+
const availablePlugins = Object.keys(registryData.registry);
|
|
378
|
+
clientLogger.debug('[usePluginDetails] Available plugins in registry:', availablePlugins);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Fetch package.json for each external plugin in parallel
|
|
382
|
+
const packageJsonPromises = externalPlugins.map(async (name) => {
|
|
383
|
+
const repoPath = getGitHubRepoPath(name, registryData);
|
|
384
|
+
const packageJson = await fetchPluginPackageJson(name, repoPath);
|
|
385
|
+
return { name, packageJson };
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const results = await Promise.all(packageJsonPromises);
|
|
389
|
+
|
|
390
|
+
// Extract required secrets for each plugin
|
|
391
|
+
for (const { name, packageJson } of results) {
|
|
392
|
+
const requiredSecrets = extractRequiredSecrets(name, packageJson);
|
|
393
|
+
details.push({
|
|
394
|
+
name,
|
|
395
|
+
requiredSecrets,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
clientLogger.debug('[usePluginDetails] Final details:', details);
|
|
401
|
+
return details;
|
|
402
|
+
},
|
|
403
|
+
enabled: pluginNames.length > 0,
|
|
404
|
+
staleTime: 5 * 60 * 1000, // Cache for 5 minutes
|
|
405
|
+
retry: 2, // Retry failed requests
|
|
406
|
+
refetchOnMount: false, // Prevent unnecessary refetches
|
|
407
|
+
refetchOnWindowFocus: false, // Prevent refetches on window focus
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Hook to get all required secrets for a list of plugins
|
|
413
|
+
*/
|
|
414
|
+
export function useRequiredSecrets(pluginNames: string[]) {
|
|
415
|
+
const { data: pluginDetails, isLoading, error } = usePluginDetails(pluginNames);
|
|
416
|
+
|
|
417
|
+
const requiredSecrets = useMemo(() => {
|
|
418
|
+
if (!pluginDetails) return [];
|
|
419
|
+
|
|
420
|
+
return pluginDetails.reduce(
|
|
421
|
+
(acc, plugin) => {
|
|
422
|
+
plugin.requiredSecrets.forEach((secret) => {
|
|
423
|
+
// Avoid duplicates
|
|
424
|
+
if (!acc.find((s) => s.name === secret.name)) {
|
|
425
|
+
acc.push({
|
|
426
|
+
...secret,
|
|
427
|
+
plugin: plugin.name,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
return acc;
|
|
432
|
+
},
|
|
433
|
+
[] as (PluginSecret & { plugin: string })[]
|
|
434
|
+
);
|
|
435
|
+
}, [pluginDetails]);
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
requiredSecrets,
|
|
439
|
+
isLoading,
|
|
440
|
+
error,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Check if all required secrets are provided
|
|
446
|
+
*/
|
|
447
|
+
export function validateRequiredSecrets(
|
|
448
|
+
requiredSecrets: PluginSecret[],
|
|
449
|
+
providedSecrets: Record<string, string | null>
|
|
450
|
+
): { isValid: boolean; missingSecrets: string[] } {
|
|
451
|
+
const missingSecrets = requiredSecrets
|
|
452
|
+
.filter((secret) => {
|
|
453
|
+
const value = providedSecrets[secret.name];
|
|
454
|
+
return !value || value.trim() === '';
|
|
455
|
+
})
|
|
456
|
+
.map((secret) => secret.name);
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
isValid: missingSecrets.length === 0,
|
|
460
|
+
missingSecrets,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { createElizaClient } from '@/lib/api-client-config';
|
|
3
|
+
import clientLogger from '@/lib/logger';
|
|
4
|
+
|
|
5
|
+
// Registry configuration - centralized for maintainability
|
|
6
|
+
const REGISTRY_ORG = 'elizaos-plugins';
|
|
7
|
+
const REGISTRY_REPO = 'registry';
|
|
8
|
+
const REGISTRY_URL = `https://raw.githubusercontent.com/${REGISTRY_ORG}/${REGISTRY_REPO}/refs/heads/main/generated-registry.json`;
|
|
9
|
+
|
|
10
|
+
interface GitVersionInfo {
|
|
11
|
+
version: string | null;
|
|
12
|
+
branch: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PluginGitInfo {
|
|
16
|
+
repo: string;
|
|
17
|
+
v0: GitVersionInfo;
|
|
18
|
+
v1: GitVersionInfo;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PluginNpmInfo {
|
|
22
|
+
repo: string;
|
|
23
|
+
v0: string | null;
|
|
24
|
+
v1: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface PluginSupport {
|
|
28
|
+
v0: boolean;
|
|
29
|
+
v1: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface PluginInfo {
|
|
33
|
+
git: PluginGitInfo;
|
|
34
|
+
npm: PluginNpmInfo;
|
|
35
|
+
supports: PluginSupport;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface RegistryResponse {
|
|
39
|
+
lastUpdatedAt: string;
|
|
40
|
+
registry: Record<string, PluginInfo>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Function to fetch plugins data from the registry API and merge with agent plugins.
|
|
45
|
+
* @returns {UseQueryResult<PluginEntry[]>} Query result containing array of plugin entries
|
|
46
|
+
*/
|
|
47
|
+
export function usePlugins() {
|
|
48
|
+
return useQuery({
|
|
49
|
+
queryKey: ['plugins'],
|
|
50
|
+
queryFn: async () => {
|
|
51
|
+
try {
|
|
52
|
+
// Fetch plugins from registry and agent data in parallel
|
|
53
|
+
const elizaClient = createElizaClient();
|
|
54
|
+
const [registryResponse, agentsResponse] = await Promise.all([
|
|
55
|
+
fetch(REGISTRY_URL),
|
|
56
|
+
elizaClient.agents.listAgents(),
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
// Process registry data
|
|
60
|
+
const registryData: RegistryResponse = await registryResponse.json();
|
|
61
|
+
|
|
62
|
+
// Extract plugin names from registry that support v1 and are plugins
|
|
63
|
+
const registryPlugins = Object.entries(registryData.registry || {})
|
|
64
|
+
.filter(([name, data]: [string, PluginInfo]) => {
|
|
65
|
+
// Check if it's a plugin and has v1 support
|
|
66
|
+
const isPlugin = name.includes('plugin');
|
|
67
|
+
const hasV1Support = data.supports.v1 === true;
|
|
68
|
+
const hasV1Version =
|
|
69
|
+
data.npm.v1 !== null || (data.git.v1.version !== null && data.git.v1.branch !== null);
|
|
70
|
+
|
|
71
|
+
return isPlugin && hasV1Support && hasV1Version;
|
|
72
|
+
})
|
|
73
|
+
.map(([name]) => name.replace(/^@elizaos-plugins\//, '@elizaos/'))
|
|
74
|
+
.sort();
|
|
75
|
+
|
|
76
|
+
// Process agent plugins from the parallel fetch
|
|
77
|
+
let agentPlugins: string[] = [];
|
|
78
|
+
try {
|
|
79
|
+
const agents = agentsResponse?.agents || [];
|
|
80
|
+
if (agents.length > 0) {
|
|
81
|
+
// Get plugins from the first active agent
|
|
82
|
+
const activeAgent = agents.find((agent) => agent.status === 'active');
|
|
83
|
+
if (activeAgent && activeAgent.id) {
|
|
84
|
+
const agentDetailResponse = await elizaClient.agents.getAgent(activeAgent.id);
|
|
85
|
+
|
|
86
|
+
// Extract plugins from the agent response
|
|
87
|
+
const plugins = (agentDetailResponse as any)?.plugins;
|
|
88
|
+
if (Array.isArray(plugins)) {
|
|
89
|
+
agentPlugins = plugins;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch (agentError) {
|
|
94
|
+
clientLogger.warn('Could not fetch agent plugins:', agentError);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Merge registry plugins with agent plugins and remove duplicates
|
|
98
|
+
const allPlugins = [...new Set([...registryPlugins, ...agentPlugins])];
|
|
99
|
+
return allPlugins.sort();
|
|
100
|
+
} catch (error) {
|
|
101
|
+
clientLogger.error('Failed to fetch from registry, falling back to basic list:', error);
|
|
102
|
+
|
|
103
|
+
// Return fallback plugins with basic info
|
|
104
|
+
return [
|
|
105
|
+
'@elizaos/plugin-bootstrap',
|
|
106
|
+
'@elizaos/plugin-evm',
|
|
107
|
+
'@elizaos/plugin-discord',
|
|
108
|
+
'@elizaos/plugin-elevenlabs',
|
|
109
|
+
'@elizaos/plugin-anthropic',
|
|
110
|
+
'@elizaos/plugin-browser',
|
|
111
|
+
'@elizaos/plugin-farcaster',
|
|
112
|
+
'@elizaos/plugin-groq',
|
|
113
|
+
]
|
|
114
|
+
.filter((name) => name.includes('plugin'))
|
|
115
|
+
.sort();
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|