miladyai 2.0.0-alpha.27
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/dist/_virtual/_rolldown/runtime.js +7 -0
- package/dist/actions/emote.js +64 -0
- package/dist/actions/restart.js +81 -0
- package/dist/actions/send-message.js +152 -0
- package/dist/agent-admin-routes.js +82 -0
- package/dist/agent-lifecycle-routes.js +79 -0
- package/dist/agent-transfer-routes.js +102 -0
- package/dist/api/agent-admin-routes.js +82 -0
- package/dist/api/agent-lifecycle-routes.js +79 -0
- package/dist/api/agent-transfer-routes.js +102 -0
- package/dist/api/apps-hyperscape-routes.js +58 -0
- package/dist/api/apps-routes.js +114 -0
- package/dist/api/auth-routes.js +56 -0
- package/dist/api/autonomy-routes.js +44 -0
- package/dist/api/bug-report-routes.js +111 -0
- package/dist/api/character-routes.js +195 -0
- package/dist/api/cloud-routes.js +330 -0
- package/dist/api/cloud-status-routes.js +155 -0
- package/dist/api/compat-utils.js +111 -0
- package/dist/api/database.js +735 -0
- package/dist/api/diagnostics-routes.js +205 -0
- package/dist/api/drop-service.js +134 -0
- package/dist/api/early-logs.js +86 -0
- package/dist/api/http-helpers.js +131 -0
- package/dist/api/knowledge-routes.js +534 -0
- package/dist/api/memory-bounds.js +71 -0
- package/dist/api/models-routes.js +28 -0
- package/dist/api/og-tracker.js +36 -0
- package/dist/api/permissions-routes.js +109 -0
- package/dist/api/plugin-validation.js +198 -0
- package/dist/api/provider-switch-config.js +41 -0
- package/dist/api/registry-routes.js +86 -0
- package/dist/api/registry-service.js +164 -0
- package/dist/api/sandbox-routes.js +1112 -0
- package/dist/api/server.js +7949 -0
- package/dist/api/subscription-routes.js +172 -0
- package/dist/api/terminal-run-limits.js +24 -0
- package/dist/api/training-routes.js +158 -0
- package/dist/api/trajectory-routes.js +300 -0
- package/dist/api/trigger-routes.js +246 -0
- package/dist/api/twitter-verify.js +134 -0
- package/dist/api/tx-service.js +108 -0
- package/dist/api/wallet-routes.js +266 -0
- package/dist/api/wallet.js +568 -0
- package/dist/api/whatsapp-routes.js +182 -0
- package/dist/api/zip-utils.js +109 -0
- package/dist/apps-hyperscape-routes.js +58 -0
- package/dist/apps-routes.js +114 -0
- package/dist/ascii.js +20 -0
- package/dist/auth/anthropic.js +44 -0
- package/dist/auth/apply-stealth.js +41 -0
- package/dist/auth/claude-code-stealth.js +78 -0
- package/dist/auth/credentials.js +156 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/openai-codex.js +66 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth-routes.js +56 -0
- package/dist/autonomy-routes.js +44 -0
- package/dist/bug-report-routes.js +111 -0
- package/dist/build-info.json +6 -0
- package/dist/character-routes.js +195 -0
- package/dist/cli/argv.js +63 -0
- package/dist/cli/banner.js +34 -0
- package/dist/cli/cli-name.js +21 -0
- package/dist/cli/cli-utils.js +16 -0
- package/dist/cli/git-commit.js +78 -0
- package/dist/cli/parse-duration.js +15 -0
- package/dist/cli/plugins-cli.js +590 -0
- package/dist/cli/profile-utils.js +9 -0
- package/dist/cli/profile.js +95 -0
- package/dist/cli/program/build-program.js +17 -0
- package/dist/cli/program/command-registry.js +23 -0
- package/dist/cli/program/help.js +47 -0
- package/dist/cli/program/preaction.js +33 -0
- package/dist/cli/program/register.config.js +106 -0
- package/dist/cli/program/register.configure.js +20 -0
- package/dist/cli/program/register.dashboard.js +124 -0
- package/dist/cli/program/register.models.js +23 -0
- package/dist/cli/program/register.setup.js +36 -0
- package/dist/cli/program/register.start.js +22 -0
- package/dist/cli/program/register.subclis.js +70 -0
- package/dist/cli/program/register.tui.js +163 -0
- package/dist/cli/program/register.update.js +154 -0
- package/dist/cli/program.js +3 -0
- package/dist/cli/run-main.js +37 -0
- package/dist/cli/version.js +7 -0
- package/dist/cloud/validate-url.js +93 -0
- package/dist/cloud-routes.js +330 -0
- package/dist/cloud-status-routes.js +155 -0
- package/dist/compat-utils.js +111 -0
- package/dist/config/config.js +69 -0
- package/dist/config/env-vars.js +19 -0
- package/dist/config/includes.js +121 -0
- package/dist/config/object-utils.js +7 -0
- package/dist/config/paths.js +38 -0
- package/dist/config/plugin-auto-enable.js +231 -0
- package/dist/config/schema.js +864 -0
- package/dist/config/telegram-custom-commands.js +76 -0
- package/dist/config/zod-schema.agent-runtime.js +519 -0
- package/dist/config/zod-schema.core.js +538 -0
- package/dist/config/zod-schema.hooks.js +103 -0
- package/dist/config/zod-schema.js +488 -0
- package/dist/config/zod-schema.providers-core.js +785 -0
- package/dist/config/zod-schema.session.js +73 -0
- package/dist/core-plugins.js +37 -0
- package/dist/custom-actions.js +250 -0
- package/dist/database.js +735 -0
- package/dist/diagnostics/integration-observability.js +57 -0
- package/dist/diagnostics-routes.js +205 -0
- package/dist/drop-service.js +134 -0
- package/dist/early-logs.js +24 -0
- package/dist/eliza.js +2061 -0
- package/dist/emotes/catalog.js +271 -0
- package/dist/entry.js +40 -0
- package/dist/hooks/discovery.js +167 -0
- package/dist/hooks/eligibility.js +64 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/loader.js +147 -0
- package/dist/hooks/registry.js +55 -0
- package/dist/http-helpers.js +131 -0
- package/dist/index.js +49 -0
- package/dist/knowledge-routes.js +534 -0
- package/dist/memory-bounds.js +71 -0
- package/dist/milady-plugin.js +90 -0
- package/dist/models-routes.js +28 -0
- package/dist/onboarding-names.js +78 -0
- package/dist/onboarding-presets.js +922 -0
- package/dist/package.json +1 -0
- package/dist/permissions-routes.js +109 -0
- package/dist/plugin-validation.js +107 -0
- package/dist/plugins/whatsapp/actions.js +91 -0
- package/dist/plugins/whatsapp/index.js +16 -0
- package/dist/plugins/whatsapp/service.js +270 -0
- package/dist/provider-switch-config.js +41 -0
- package/dist/providers/admin-trust.js +46 -0
- package/dist/providers/autonomous-state.js +101 -0
- package/dist/providers/session-bridge.js +86 -0
- package/dist/providers/session-utils.js +36 -0
- package/dist/providers/simple-mode.js +50 -0
- package/dist/providers/ui-catalog.js +15 -0
- package/dist/providers/workspace-provider.js +93 -0
- package/dist/providers/workspace.js +348 -0
- package/dist/registry-routes.js +86 -0
- package/dist/registry-service.js +164 -0
- package/dist/restart.js +40 -0
- package/dist/runtime/core-plugins.js +37 -0
- package/dist/runtime/custom-actions.js +250 -0
- package/dist/runtime/eliza.js +2061 -0
- package/dist/runtime/embedding-manager-support.js +185 -0
- package/dist/runtime/embedding-manager.js +193 -0
- package/dist/runtime/embedding-presets.js +54 -0
- package/dist/runtime/embedding-state.js +8 -0
- package/dist/runtime/milady-plugin.js +90 -0
- package/dist/runtime/onboarding-names.js +78 -0
- package/dist/runtime/restart.js +40 -0
- package/dist/runtime/version.js +7 -0
- package/dist/sandbox-routes.js +1112 -0
- package/dist/security/audit-log.js +149 -0
- package/dist/security/network-policy.js +70 -0
- package/dist/server.js +7949 -0
- package/dist/services/agent-export.js +559 -0
- package/dist/services/app-manager.js +389 -0
- package/dist/services/browser-capture.js +86 -0
- package/dist/services/fallback-training-service.js +128 -0
- package/dist/services/mcp-marketplace.js +134 -0
- package/dist/services/plugin-installer.js +396 -0
- package/dist/services/plugin-manager-types.js +15 -0
- package/dist/services/registry-client-app-meta.js +144 -0
- package/dist/services/registry-client-endpoints.js +166 -0
- package/dist/services/registry-client-local.js +271 -0
- package/dist/services/registry-client-network.js +93 -0
- package/dist/services/registry-client-queries.js +70 -0
- package/dist/services/registry-client.js +157 -0
- package/dist/services/sandbox-engine.js +511 -0
- package/dist/services/sandbox-manager.js +297 -0
- package/dist/services/self-updater.js +175 -0
- package/dist/services/skill-catalog-client.js +119 -0
- package/dist/services/skill-marketplace.js +521 -0
- package/dist/services/stream-manager.js +236 -0
- package/dist/services/update-checker.js +121 -0
- package/dist/services/update-notifier.js +29 -0
- package/dist/services/version-compat.js +78 -0
- package/dist/services/whatsapp-pairing.js +196 -0
- package/dist/shared/ui-catalog-prompt.js +728 -0
- package/dist/subscription-routes.js +172 -0
- package/dist/terminal/links.js +19 -0
- package/dist/terminal/palette.js +14 -0
- package/dist/terminal/theme.js +25 -0
- package/dist/terminal-run-limits.js +24 -0
- package/dist/training-routes.js +158 -0
- package/dist/trajectory-routes.js +300 -0
- package/dist/trigger-routes.js +246 -0
- package/dist/triggers/action.js +218 -0
- package/dist/triggers/runtime.js +281 -0
- package/dist/triggers/scheduling.js +295 -0
- package/dist/triggers/types.js +5 -0
- package/dist/tui/components/assistant-message.js +76 -0
- package/dist/tui/components/chat-editor.js +34 -0
- package/dist/tui/components/embeddings-overlay.js +46 -0
- package/dist/tui/components/footer.js +60 -0
- package/dist/tui/components/index.js +15 -0
- package/dist/tui/components/modal-frame.js +45 -0
- package/dist/tui/components/modal-style.js +15 -0
- package/dist/tui/components/model-selector.js +70 -0
- package/dist/tui/components/pinned-chat-layout.js +46 -0
- package/dist/tui/components/plugins-endpoints-tab.js +196 -0
- package/dist/tui/components/plugins-installed-tab-view.js +69 -0
- package/dist/tui/components/plugins-installed-tab.js +319 -0
- package/dist/tui/components/plugins-overlay-catalog.js +81 -0
- package/dist/tui/components/plugins-overlay-data-api.js +21 -0
- package/dist/tui/components/plugins-overlay-data-shared.js +20 -0
- package/dist/tui/components/plugins-overlay-data.js +323 -0
- package/dist/tui/components/plugins-overlay.js +117 -0
- package/dist/tui/components/plugins-store-tab.js +148 -0
- package/dist/tui/components/settings-overlay.js +61 -0
- package/dist/tui/components/status-bar.js +64 -0
- package/dist/tui/components/tool-execution.js +68 -0
- package/dist/tui/components/user-message.js +22 -0
- package/dist/tui/eliza-tui-bridge.js +606 -0
- package/dist/tui/index.js +370 -0
- package/dist/tui/modal-presets.js +33 -0
- package/dist/tui/model-spec.js +46 -0
- package/dist/tui/sse-parser.js +78 -0
- package/dist/tui/theme.js +110 -0
- package/dist/tui/titlebar-spinner.js +62 -0
- package/dist/tui/tui-app.js +311 -0
- package/dist/tui/ws-client.js +215 -0
- package/dist/twitter-verify.js +134 -0
- package/dist/tx-service.js +108 -0
- package/dist/utils/exec-safety.js +17 -0
- package/dist/utils/globals.js +20 -0
- package/dist/utils/milady-root.js +61 -0
- package/dist/utils/number-parsing.js +37 -0
- package/dist/version-resolver.js +37 -0
- package/dist/version.js +7 -0
- package/dist/wallet-routes.js +266 -0
- package/dist/wallet.js +568 -0
- package/dist/whatsapp-routes.js +182 -0
- package/dist/zip-utils.js +109 -0
- package/milady.mjs +14 -0
- package/package.json +111 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
//#region src/tui/components/plugins-overlay-catalog.ts
|
|
6
|
+
let pluginCatalogCache = null;
|
|
7
|
+
function inferSensitiveKey(key) {
|
|
8
|
+
const upper = key.toUpperCase();
|
|
9
|
+
return upper.includes("_API_KEY") || upper.includes("_SECRET") || upper.includes("_TOKEN") || upper.includes("_PASSWORD") || upper.includes("_PRIVATE_KEY") || upper.includes("_SIGNING_") || upper.includes("ENCRYPTION_");
|
|
10
|
+
}
|
|
11
|
+
function inferRequiredKey(key, sensitive) {
|
|
12
|
+
if (!sensitive) return false;
|
|
13
|
+
const upper = key.toUpperCase();
|
|
14
|
+
return upper.endsWith("_API_KEY") || upper.endsWith("_BOT_TOKEN") || upper.endsWith("_TOKEN") || upper.endsWith("_PRIVATE_KEY");
|
|
15
|
+
}
|
|
16
|
+
function findPackageRoot(startDir) {
|
|
17
|
+
let dir = startDir;
|
|
18
|
+
for (let i = 0; i < 10; i++) {
|
|
19
|
+
const pkgPath = path.join(dir, "package.json");
|
|
20
|
+
if (fs.existsSync(pkgPath)) try {
|
|
21
|
+
if (JSON.parse(fs.readFileSync(pkgPath, "utf-8")).name === "milady") return dir;
|
|
22
|
+
} catch {}
|
|
23
|
+
const parent = path.dirname(dir);
|
|
24
|
+
if (parent === dir) break;
|
|
25
|
+
dir = parent;
|
|
26
|
+
}
|
|
27
|
+
return startDir;
|
|
28
|
+
}
|
|
29
|
+
function buildPluginCatalogIndex() {
|
|
30
|
+
if (pluginCatalogCache) return pluginCatalogCache;
|
|
31
|
+
const packageRoot = findPackageRoot(import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url)));
|
|
32
|
+
const manifestPath = path.join(packageRoot, "plugins.json");
|
|
33
|
+
const map = /* @__PURE__ */ new Map();
|
|
34
|
+
if (!fs.existsSync(manifestPath)) {
|
|
35
|
+
pluginCatalogCache = map;
|
|
36
|
+
return map;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const data = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
40
|
+
for (const entry of data.plugins ?? []) {
|
|
41
|
+
map.set(entry.id, entry);
|
|
42
|
+
if (entry.npmName) map.set(entry.npmName, entry);
|
|
43
|
+
if (entry.id.startsWith("plugin-")) map.set(`@elizaos/${entry.id}`, entry);
|
|
44
|
+
else {
|
|
45
|
+
map.set(`plugin-${entry.id}`, entry);
|
|
46
|
+
map.set(`@elizaos/plugin-${entry.id}`, entry);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch {}
|
|
50
|
+
pluginCatalogCache = map;
|
|
51
|
+
return map;
|
|
52
|
+
}
|
|
53
|
+
function readInstalledPluginMetadata(packageName, installPath) {
|
|
54
|
+
if (!installPath) return {
|
|
55
|
+
configKeys: [],
|
|
56
|
+
pluginParameters: {},
|
|
57
|
+
configUiHints: {}
|
|
58
|
+
};
|
|
59
|
+
const pkgJsonCandidates = [path.join(installPath, "node_modules", ...packageName.split("/"), "package.json"), path.join(installPath, "package.json")];
|
|
60
|
+
for (const pkgPath of pkgJsonCandidates) {
|
|
61
|
+
if (!fs.existsSync(pkgPath)) continue;
|
|
62
|
+
try {
|
|
63
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
64
|
+
const pluginParameters = pkg.pluginParameters ?? pkg.elizaos?.pluginParameters ?? pkg.agentConfig?.pluginParameters ?? {};
|
|
65
|
+
const configUiHints = pkg.configUiHints ?? pkg.elizaos?.configUiHints ?? {};
|
|
66
|
+
return {
|
|
67
|
+
configKeys: Array.from(new Set([...pkg.elizaos?.configKeys ?? [], ...Object.keys(pluginParameters)])),
|
|
68
|
+
pluginParameters,
|
|
69
|
+
configUiHints
|
|
70
|
+
};
|
|
71
|
+
} catch {}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
configKeys: [],
|
|
75
|
+
pluginParameters: {},
|
|
76
|
+
configUiHints: {}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
export { buildPluginCatalogIndex, inferRequiredKey, inferSensitiveKey, readInstalledPluginMetadata };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/tui/components/plugins-overlay-data-api.ts
|
|
2
|
+
async function installPluginViaApiRequest(request, name) {
|
|
3
|
+
const response = await request("/api/plugins/install", {
|
|
4
|
+
method: "POST",
|
|
5
|
+
body: JSON.stringify({ name })
|
|
6
|
+
});
|
|
7
|
+
if (!response.ok) return {
|
|
8
|
+
success: false,
|
|
9
|
+
message: response.error ?? `Failed to install ${name}`
|
|
10
|
+
};
|
|
11
|
+
const pluginName = response.plugin?.name ?? name;
|
|
12
|
+
const version = response.plugin?.version;
|
|
13
|
+
const restartHint = response.requiresRestart ? " Restart milady to load it." : "";
|
|
14
|
+
return {
|
|
15
|
+
success: true,
|
|
16
|
+
message: response.message ?? `${pluginName}${version ? `@${version}` : ""} installed.${restartHint}`
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { installPluginViaApiRequest };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/tui/components/plugins-overlay-data-shared.ts
|
|
2
|
+
const API_MASKED_SENTINEL = "__MILADY_API_MASKED__";
|
|
3
|
+
function registerPluginNameVariants(names, rawName) {
|
|
4
|
+
const trimmed = rawName.trim();
|
|
5
|
+
if (!trimmed) return;
|
|
6
|
+
names.add(trimmed);
|
|
7
|
+
const normalized = trimmed.replace(/^@[^/]+\//, "").replace(/^plugin-/, "").trim();
|
|
8
|
+
if (!normalized) return;
|
|
9
|
+
names.add(normalized);
|
|
10
|
+
names.add(`plugin-${normalized}`);
|
|
11
|
+
names.add(`@elizaos/plugin-${normalized}`);
|
|
12
|
+
}
|
|
13
|
+
function matchesInstalledPluginName(candidates, installedName) {
|
|
14
|
+
if (candidates.has(installedName)) return true;
|
|
15
|
+
const normalized = installedName.replace(/^@[^/]+\//, "").replace(/^plugin-/, "").trim();
|
|
16
|
+
return normalized.length > 0 && candidates.has(normalized);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { API_MASKED_SENTINEL, matchesInstalledPluginName, registerPluginNameVariants };
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { loadMiladyConfig, saveMiladyConfig } from "../../config/config.js";
|
|
2
|
+
import { getRegistryPlugins } from "../../services/registry-client.js";
|
|
3
|
+
import { installPlugin } from "../../services/plugin-installer.js";
|
|
4
|
+
import { buildPluginCatalogIndex, inferRequiredKey, inferSensitiveKey, readInstalledPluginMetadata } from "./plugins-overlay-catalog.js";
|
|
5
|
+
import { installPluginViaApiRequest } from "./plugins-overlay-data-api.js";
|
|
6
|
+
import { API_MASKED_SENTINEL, matchesInstalledPluginName, registerPluginNameVariants } from "./plugins-overlay-data-shared.js";
|
|
7
|
+
|
|
8
|
+
//#region src/tui/components/plugins-overlay-data.ts
|
|
9
|
+
var PluginsOverlayDataBridge = class {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.apiInstalledPluginNames = /* @__PURE__ */ new Set();
|
|
13
|
+
}
|
|
14
|
+
getApiBaseUrl() {
|
|
15
|
+
const base = this.options.apiBaseUrl?.trim() || process.env.MILADY_API_BASE_URL?.trim() || process.env.MILADY_API_BASE?.trim();
|
|
16
|
+
if (!base) return null;
|
|
17
|
+
return base.replace(/\/+$/, "");
|
|
18
|
+
}
|
|
19
|
+
getApiToken() {
|
|
20
|
+
const token = process.env.MILADY_API_TOKEN?.trim();
|
|
21
|
+
return token ? token : null;
|
|
22
|
+
}
|
|
23
|
+
async apiFetchJson(apiBaseUrl, routePath, init) {
|
|
24
|
+
const headers = new Headers(init?.headers);
|
|
25
|
+
if (init?.body != null && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");
|
|
26
|
+
const token = this.getApiToken();
|
|
27
|
+
if (token && !headers.has("Authorization")) headers.set("Authorization", `Bearer ${token}`);
|
|
28
|
+
const res = await fetch(`${apiBaseUrl}${routePath}`, {
|
|
29
|
+
...init,
|
|
30
|
+
headers
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
let message = `HTTP ${res.status}`;
|
|
34
|
+
try {
|
|
35
|
+
const body = await res.json();
|
|
36
|
+
if (typeof body.error === "string" && body.error.trim()) message = body.error;
|
|
37
|
+
else if (Array.isArray(body.validationErrors)) {
|
|
38
|
+
const first = body.validationErrors[0];
|
|
39
|
+
if (first?.message) message = first.message;
|
|
40
|
+
}
|
|
41
|
+
} catch {}
|
|
42
|
+
throw new Error(message);
|
|
43
|
+
}
|
|
44
|
+
return res.json();
|
|
45
|
+
}
|
|
46
|
+
async getInstalledPlugins() {
|
|
47
|
+
const apiBaseUrl = this.getApiBaseUrl();
|
|
48
|
+
if (apiBaseUrl) try {
|
|
49
|
+
return await this.getInstalledPluginsFromApi(apiBaseUrl);
|
|
50
|
+
} catch {}
|
|
51
|
+
return this.getInstalledPluginsFromConfig();
|
|
52
|
+
}
|
|
53
|
+
registerInstalledPluginName(name) {
|
|
54
|
+
registerPluginNameVariants(this.apiInstalledPluginNames, name);
|
|
55
|
+
}
|
|
56
|
+
async loadApiInstalledPlugins(apiBaseUrl) {
|
|
57
|
+
try {
|
|
58
|
+
const plugins = (await this.apiFetchJson(apiBaseUrl, "/api/plugins/installed")).plugins ?? [];
|
|
59
|
+
this.apiInstalledPluginNames.clear();
|
|
60
|
+
for (const plugin of plugins) if (plugin.name) this.registerInstalledPluginName(plugin.name);
|
|
61
|
+
return plugins;
|
|
62
|
+
} catch {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async getInstalledPluginsFromApi(apiBaseUrl) {
|
|
67
|
+
const installed = await this.loadApiInstalledPlugins(apiBaseUrl);
|
|
68
|
+
let response;
|
|
69
|
+
try {
|
|
70
|
+
response = await this.apiFetchJson(apiBaseUrl, "/api/plugins");
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (installed.length === 0) throw err;
|
|
73
|
+
const fallbackItems = [];
|
|
74
|
+
for (const plugin of installed) {
|
|
75
|
+
const name = plugin.name?.trim();
|
|
76
|
+
if (!name) continue;
|
|
77
|
+
const id = name.replace(/^@[^/]+\//, "").replace(/^plugin-/, "");
|
|
78
|
+
fallbackItems.push({
|
|
79
|
+
id: id || name,
|
|
80
|
+
name,
|
|
81
|
+
description: "",
|
|
82
|
+
enabled: true,
|
|
83
|
+
category: "plugin",
|
|
84
|
+
version: plugin.version ?? "unknown",
|
|
85
|
+
configStatus: {
|
|
86
|
+
set: 0,
|
|
87
|
+
total: 0
|
|
88
|
+
},
|
|
89
|
+
parameters: []
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return fallbackItems;
|
|
93
|
+
}
|
|
94
|
+
const plugins = response.plugins ?? [];
|
|
95
|
+
const matchedInstalled = /* @__PURE__ */ new Set();
|
|
96
|
+
const items = plugins.map((plugin) => {
|
|
97
|
+
const pluginId = plugin.id?.trim() || plugin.name?.trim() || "plugin";
|
|
98
|
+
const npmName = plugin.npmName?.trim();
|
|
99
|
+
if (npmName) this.registerInstalledPluginName(npmName);
|
|
100
|
+
if (pluginId) this.registerInstalledPluginName(pluginId);
|
|
101
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
102
|
+
if (pluginId) {
|
|
103
|
+
candidates.add(pluginId);
|
|
104
|
+
candidates.add(`plugin-${pluginId}`);
|
|
105
|
+
candidates.add(`@elizaos/plugin-${pluginId}`);
|
|
106
|
+
}
|
|
107
|
+
if (npmName) candidates.add(npmName);
|
|
108
|
+
let installedVersion;
|
|
109
|
+
for (const entry of installed) {
|
|
110
|
+
const installedName = entry.name?.trim();
|
|
111
|
+
if (!installedName) continue;
|
|
112
|
+
if (!matchesInstalledPluginName(candidates, installedName)) continue;
|
|
113
|
+
matchedInstalled.add(installedName);
|
|
114
|
+
installedVersion = entry.version ?? installedVersion;
|
|
115
|
+
}
|
|
116
|
+
const parameters = (plugin.parameters ?? []).map((param) => {
|
|
117
|
+
const key = param.key;
|
|
118
|
+
const hint = plugin.configUiHints?.[key];
|
|
119
|
+
const options = Array.isArray(hint?.options) ? hint.options.map((opt) => {
|
|
120
|
+
if (typeof opt === "string") return opt;
|
|
121
|
+
if (typeof opt === "object" && opt !== null) {
|
|
122
|
+
const value = opt.value;
|
|
123
|
+
if (typeof value === "string") return value;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}).filter((v) => typeof v === "string") : void 0;
|
|
127
|
+
return {
|
|
128
|
+
key,
|
|
129
|
+
label: typeof hint?.label === "string" && hint.label.trim() ? hint.label : key,
|
|
130
|
+
value: param.sensitive && param.isSet ? API_MASKED_SENTINEL : param.currentValue ?? "",
|
|
131
|
+
required: param.required,
|
|
132
|
+
sensitive: param.sensitive,
|
|
133
|
+
values: options
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
id: pluginId,
|
|
138
|
+
name: plugin.name || pluginId,
|
|
139
|
+
description: plugin.description ?? "",
|
|
140
|
+
enabled: plugin.enabled !== false,
|
|
141
|
+
category: plugin.category ?? "plugin",
|
|
142
|
+
version: plugin.version ?? installedVersion ?? "unknown",
|
|
143
|
+
configStatus: {
|
|
144
|
+
set: (plugin.parameters ?? []).filter((p) => p.isSet).length,
|
|
145
|
+
total: (plugin.parameters ?? []).length
|
|
146
|
+
},
|
|
147
|
+
parameters
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
for (const entry of installed) {
|
|
151
|
+
const installedName = entry.name?.trim();
|
|
152
|
+
if (!installedName || matchedInstalled.has(installedName)) continue;
|
|
153
|
+
const id = installedName.replace(/^@[^/]+\//, "").replace(/^plugin-/, "").trim();
|
|
154
|
+
items.push({
|
|
155
|
+
id: id || installedName,
|
|
156
|
+
name: installedName,
|
|
157
|
+
description: "",
|
|
158
|
+
enabled: true,
|
|
159
|
+
category: "plugin",
|
|
160
|
+
version: entry.version ?? "unknown",
|
|
161
|
+
configStatus: {
|
|
162
|
+
set: 0,
|
|
163
|
+
total: 0
|
|
164
|
+
},
|
|
165
|
+
parameters: []
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return items;
|
|
169
|
+
}
|
|
170
|
+
async getInstalledPluginsFromConfig() {
|
|
171
|
+
const cfg = loadMiladyConfig();
|
|
172
|
+
const entries = cfg.plugins?.entries ?? {};
|
|
173
|
+
const installs = cfg.plugins?.installs ?? {};
|
|
174
|
+
const catalog = buildPluginCatalogIndex();
|
|
175
|
+
const plugins = [];
|
|
176
|
+
const allIds = new Set([...Object.keys(entries), ...Object.keys(installs)]);
|
|
177
|
+
for (const id of allIds) {
|
|
178
|
+
const entry = entries[id];
|
|
179
|
+
const install = installs[id];
|
|
180
|
+
const config = entry?.config ?? {};
|
|
181
|
+
const catalogEntry = catalog.get(id);
|
|
182
|
+
const installedMeta = readInstalledPluginMetadata(id, install?.installPath);
|
|
183
|
+
const mergedParamDefs = {
|
|
184
|
+
...catalogEntry?.pluginParameters ?? {},
|
|
185
|
+
...installedMeta.pluginParameters
|
|
186
|
+
};
|
|
187
|
+
const mergedHints = {
|
|
188
|
+
...catalogEntry?.configUiHints ?? {},
|
|
189
|
+
...installedMeta.configUiHints
|
|
190
|
+
};
|
|
191
|
+
const declaredKeys = [
|
|
192
|
+
...catalogEntry?.configKeys ?? [],
|
|
193
|
+
...installedMeta.configKeys,
|
|
194
|
+
...Object.keys(mergedParamDefs)
|
|
195
|
+
];
|
|
196
|
+
const keySet = new Set([...declaredKeys, ...Object.keys(config)]);
|
|
197
|
+
const parameters = Array.from(keySet).sort((a, b) => a.localeCompare(b)).map((key) => {
|
|
198
|
+
const valueFromConfig = config[key];
|
|
199
|
+
const value = valueFromConfig != null && valueFromConfig !== "" ? String(valueFromConfig) : process.env[key] ?? "";
|
|
200
|
+
const hint = mergedHints[key];
|
|
201
|
+
const paramDef = mergedParamDefs[key];
|
|
202
|
+
const sensitive = typeof paramDef?.sensitive === "boolean" ? paramDef.sensitive : inferSensitiveKey(key);
|
|
203
|
+
const required = typeof paramDef?.required === "boolean" ? paramDef.required : inferRequiredKey(key, sensitive);
|
|
204
|
+
return {
|
|
205
|
+
key,
|
|
206
|
+
label: hint?.label ?? key,
|
|
207
|
+
value,
|
|
208
|
+
required,
|
|
209
|
+
sensitive
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
plugins.push({
|
|
213
|
+
id,
|
|
214
|
+
name: id,
|
|
215
|
+
description: install?.spec ?? catalogEntry?.description ?? "",
|
|
216
|
+
enabled: entry?.enabled !== false,
|
|
217
|
+
category: id.includes("plugin-") ? "plugin" : "extension",
|
|
218
|
+
version: install?.version ?? "unknown",
|
|
219
|
+
configStatus: {
|
|
220
|
+
set: parameters.filter((p) => p.value.trim() !== "").length,
|
|
221
|
+
total: parameters.length
|
|
222
|
+
},
|
|
223
|
+
parameters
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return plugins;
|
|
227
|
+
}
|
|
228
|
+
async togglePluginEnabled(id, enabled) {
|
|
229
|
+
const apiBaseUrl = this.getApiBaseUrl();
|
|
230
|
+
if (apiBaseUrl) {
|
|
231
|
+
await this.apiFetchJson(apiBaseUrl, `/api/plugins/${encodeURIComponent(id)}`, {
|
|
232
|
+
method: "PUT",
|
|
233
|
+
body: JSON.stringify({ enabled })
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const cfg = loadMiladyConfig();
|
|
238
|
+
if (!cfg.plugins) cfg.plugins = {};
|
|
239
|
+
if (!cfg.plugins.entries) cfg.plugins.entries = {};
|
|
240
|
+
if (!cfg.plugins.entries[id]) cfg.plugins.entries[id] = {};
|
|
241
|
+
cfg.plugins.entries[id].enabled = enabled;
|
|
242
|
+
saveMiladyConfig(cfg);
|
|
243
|
+
}
|
|
244
|
+
async savePluginConfig(id, config) {
|
|
245
|
+
const apiBaseUrl = this.getApiBaseUrl();
|
|
246
|
+
if (apiBaseUrl) {
|
|
247
|
+
const filteredConfig = Object.fromEntries(Object.entries(config).filter(([, value]) => value !== API_MASKED_SENTINEL));
|
|
248
|
+
await this.apiFetchJson(apiBaseUrl, `/api/plugins/${encodeURIComponent(id)}`, {
|
|
249
|
+
method: "PUT",
|
|
250
|
+
body: JSON.stringify({ config: filteredConfig })
|
|
251
|
+
});
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const cfg = loadMiladyConfig();
|
|
255
|
+
if (!cfg.plugins) cfg.plugins = {};
|
|
256
|
+
if (!cfg.plugins.entries) cfg.plugins.entries = {};
|
|
257
|
+
if (!cfg.plugins.entries[id]) cfg.plugins.entries[id] = {};
|
|
258
|
+
cfg.plugins.entries[id].config = config;
|
|
259
|
+
saveMiladyConfig(cfg);
|
|
260
|
+
}
|
|
261
|
+
async installPlugin(name) {
|
|
262
|
+
const apiBaseUrl = this.getApiBaseUrl();
|
|
263
|
+
if (apiBaseUrl) return installPluginViaApiRequest((routePath, init) => this.apiFetchJson(apiBaseUrl, routePath, init), name);
|
|
264
|
+
const result = await installPlugin(name);
|
|
265
|
+
if (!result.success) return {
|
|
266
|
+
success: false,
|
|
267
|
+
message: result.error ?? `Failed to install ${name}`
|
|
268
|
+
};
|
|
269
|
+
const restartHint = result.requiresRestart ? " Restart milady to load it." : "";
|
|
270
|
+
return {
|
|
271
|
+
success: true,
|
|
272
|
+
message: `${result.pluginName}@${result.version} installed.${restartHint}`
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
async getStorePlugins() {
|
|
276
|
+
const apiBaseUrl = this.getApiBaseUrl();
|
|
277
|
+
if (apiBaseUrl) await this.loadApiInstalledPlugins(apiBaseUrl);
|
|
278
|
+
const registry = await getRegistryPlugins();
|
|
279
|
+
const installs = loadMiladyConfig().plugins?.installs ?? {};
|
|
280
|
+
const items = [];
|
|
281
|
+
for (const [, p] of registry) {
|
|
282
|
+
if (p.kind === "app") continue;
|
|
283
|
+
items.push({
|
|
284
|
+
name: p.name,
|
|
285
|
+
description: p.description,
|
|
286
|
+
latestVersion: p.npm.v2Version || p.npm.v1Version || p.npm.v0Version,
|
|
287
|
+
stars: p.stars,
|
|
288
|
+
supports: p.supports,
|
|
289
|
+
installed: this.isPluginInstalled(p.name) || p.name in installs
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
items.sort((a, b) => b.stars - a.stars);
|
|
293
|
+
return items;
|
|
294
|
+
}
|
|
295
|
+
async searchStore(query, limit = 15) {
|
|
296
|
+
const apiBaseUrl = this.getApiBaseUrl();
|
|
297
|
+
if (apiBaseUrl) await this.loadApiInstalledPlugins(apiBaseUrl);
|
|
298
|
+
const { searchNonAppPlugins } = await import("../../services/registry-client.js");
|
|
299
|
+
const results = await searchNonAppPlugins(query, limit);
|
|
300
|
+
const installs = loadMiladyConfig().plugins?.installs ?? {};
|
|
301
|
+
return results.map((r) => ({
|
|
302
|
+
name: r.name,
|
|
303
|
+
description: r.description,
|
|
304
|
+
latestVersion: r.latestVersion,
|
|
305
|
+
stars: r.stars,
|
|
306
|
+
supports: r.supports,
|
|
307
|
+
installed: this.isPluginInstalled(r.name) || r.name in installs
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
isPluginInstalled(name) {
|
|
311
|
+
if (this.apiInstalledPluginNames.has(name)) return true;
|
|
312
|
+
const normalized = name.replace(/^@[^/]+\//, "").replace(/^plugin-/, "");
|
|
313
|
+
if (normalized && this.apiInstalledPluginNames.has(normalized)) return true;
|
|
314
|
+
try {
|
|
315
|
+
return name in (loadMiladyConfig().plugins?.installs ?? {});
|
|
316
|
+
} catch {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
//#endregion
|
|
323
|
+
export { PluginsOverlayDataBridge };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { addRegistryEndpoint, getConfiguredEndpoints, isDefaultEndpoint, removeRegistryEndpoint, toggleRegistryEndpoint } from "../../services/registry-client.js";
|
|
2
|
+
import { tuiTheme } from "../theme.js";
|
|
3
|
+
import { ModalFrame } from "./modal-frame.js";
|
|
4
|
+
import { PluginEndpointsTab } from "./plugins-endpoints-tab.js";
|
|
5
|
+
import { InstalledPluginsTab } from "./plugins-installed-tab.js";
|
|
6
|
+
import { PluginsOverlayDataBridge } from "./plugins-overlay-data.js";
|
|
7
|
+
import { PluginStoreTab } from "./plugins-store-tab.js";
|
|
8
|
+
import { getEditorKeybindings } from "@mariozechner/pi-tui";
|
|
9
|
+
|
|
10
|
+
//#region src/tui/components/plugins-overlay.ts
|
|
11
|
+
const TAB_NAMES = [
|
|
12
|
+
"Installed",
|
|
13
|
+
"Store",
|
|
14
|
+
"Endpoints"
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Main Plugins overlay with three tabs: Installed, Store, Endpoints.
|
|
18
|
+
* Accessible via `/plugins` or Ctrl+L.
|
|
19
|
+
*/
|
|
20
|
+
var PluginsOverlayComponent = class {
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.focused = false;
|
|
24
|
+
this.activeTab = 0;
|
|
25
|
+
this.frame = new ModalFrame({
|
|
26
|
+
title: "Plugins",
|
|
27
|
+
hint: "↑↓ navigate • Tab switch tabs • Enter select • Esc close"
|
|
28
|
+
});
|
|
29
|
+
this.data = new PluginsOverlayDataBridge(options);
|
|
30
|
+
const render = () => options.requestRender();
|
|
31
|
+
this.tabs = [
|
|
32
|
+
new InstalledPluginsTab({
|
|
33
|
+
getPlugins: () => this.data.getInstalledPlugins(),
|
|
34
|
+
onTogglePlugin: async (id, enabled) => {
|
|
35
|
+
await this.data.togglePluginEnabled(id, enabled);
|
|
36
|
+
},
|
|
37
|
+
onConfigSave: async (id, config) => {
|
|
38
|
+
await this.data.savePluginConfig(id, config);
|
|
39
|
+
},
|
|
40
|
+
onClose: () => options.onClose(),
|
|
41
|
+
requestRender: render
|
|
42
|
+
}),
|
|
43
|
+
new PluginStoreTab({
|
|
44
|
+
searchPlugins: async (query, limit) => this.data.searchStore(query, limit),
|
|
45
|
+
getRegistryPlugins: async () => this.data.getStorePlugins(),
|
|
46
|
+
installPlugin: async (name) => this.data.installPlugin(name),
|
|
47
|
+
isInstalled: (name) => this.data.isPluginInstalled(name),
|
|
48
|
+
onClose: () => options.onClose(),
|
|
49
|
+
requestRender: render
|
|
50
|
+
}),
|
|
51
|
+
new PluginEndpointsTab({
|
|
52
|
+
getEndpoints: () => getConfiguredEndpoints(),
|
|
53
|
+
addEndpoint: (label, url) => addRegistryEndpoint(label, url),
|
|
54
|
+
removeEndpoint: (url) => removeRegistryEndpoint(url),
|
|
55
|
+
toggleEndpoint: (url, enabled) => toggleRegistryEndpoint(url, enabled),
|
|
56
|
+
isDefaultEndpoint: (url) => isDefaultEndpoint(url),
|
|
57
|
+
onClose: () => options.onClose(),
|
|
58
|
+
requestRender: render
|
|
59
|
+
})
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
switchTab(index) {
|
|
63
|
+
this.activeTab = index;
|
|
64
|
+
this.options.requestRender();
|
|
65
|
+
}
|
|
66
|
+
handleInput(data) {
|
|
67
|
+
const kb = getEditorKeybindings();
|
|
68
|
+
const tab = this.tabs[this.activeTab];
|
|
69
|
+
tab.focused = this.focused;
|
|
70
|
+
if (tab.isCapturingInput()) {
|
|
71
|
+
tab.handleInput(data);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (kb.matches(data, "selectCancel")) {
|
|
75
|
+
this.options.onClose();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (data === " ") {
|
|
79
|
+
this.switchTab((this.activeTab + 1) % 3);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (data === "1") {
|
|
83
|
+
this.switchTab(0);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (data === "2") {
|
|
87
|
+
this.switchTab(1);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (data === "3") {
|
|
91
|
+
this.switchTab(2);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
tab.handleInput(data);
|
|
95
|
+
}
|
|
96
|
+
render(width) {
|
|
97
|
+
const body = [];
|
|
98
|
+
const tabBar = TAB_NAMES.map((name, i) => {
|
|
99
|
+
const isActive = i === this.activeTab;
|
|
100
|
+
const num = `${i + 1}`;
|
|
101
|
+
if (isActive) return tuiTheme.accent(`[${num}:${name}]`);
|
|
102
|
+
return tuiTheme.dim(` ${num}:${name} `);
|
|
103
|
+
}).join(" ");
|
|
104
|
+
body.push(` ${tabBar}`);
|
|
105
|
+
body.push("");
|
|
106
|
+
const tab = this.tabs[this.activeTab];
|
|
107
|
+
tab.focused = this.focused;
|
|
108
|
+
body.push(...tab.render(width));
|
|
109
|
+
return this.frame.render(width, body);
|
|
110
|
+
}
|
|
111
|
+
invalidate() {
|
|
112
|
+
for (const tab of this.tabs) tab.invalidate();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
//#endregion
|
|
117
|
+
export { PluginsOverlayComponent };
|