@elizaos/cli 1.0.15 → 1.0.16
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/assets/{index-CYy-fwbh.js → index-BBiLesJT.js} +3 -3
- package/dist/assets/index-BBiLesJT.js.br +0 -0
- package/dist/assets/{index-CYy-fwbh.js.map → index-BBiLesJT.js.map} +1 -1
- package/dist/assets/index-DxW_jg81.css +1 -0
- package/dist/assets/index-DxW_jg81.css.br +0 -0
- package/dist/assets/{index-TE3LspKB.js → index-EfDd1Y35.js} +2103 -1818
- package/dist/assets/index-EfDd1Y35.js.br +0 -0
- package/dist/assets/{index-TE3LspKB.js.map → index-EfDd1Y35.js.map} +1 -1
- package/dist/assets/{vendor-DSdxb8P-.js → vendor-DS2z8upE.js} +2 -2
- package/dist/assets/vendor-DS2z8upE.js.br +0 -0
- package/dist/assets/{vendor-DSdxb8P-.js.map → vendor-DS2z8upE.js.map} +1 -1
- package/dist/{chunk-AZUBN22B.js → chunk-OK5O2MHJ.js} +503 -705
- package/dist/{chunk-OXZUNMVC.js → chunk-PRO6QOLZ.js} +175 -48
- package/dist/{chunk-BRDZOULQ.js → chunk-UVBNT4WP.js} +19 -6
- package/dist/{chunk-KB3JDWUI.js → chunk-W4NJVJQV.js} +43 -1
- package/dist/commands/agent/actions/index.js +2 -3
- package/dist/commands/agent/index.js +2 -3
- package/dist/commands/create/actions/index.d.ts +3 -0
- package/dist/commands/create/actions/index.js +3 -4
- package/dist/commands/create/index.js +4 -5
- package/dist/elizaos-avatar.png +0 -0
- package/dist/index.html +3 -3
- package/dist/index.js +1462 -381
- package/dist/migration-guides/advanced-migration-guide.md +459 -0
- package/dist/migration-guides/completion-requirements.md +379 -0
- package/dist/migration-guides/integrated-migration-loop.md +392 -0
- package/dist/migration-guides/migration-guide.md +712 -0
- package/dist/migration-guides/prompt-and-generation-guide.md +702 -0
- package/dist/migration-guides/state-and-providers-guide.md +544 -0
- package/dist/migration-guides/testing-guide.md +1021 -0
- package/dist/{plugin-creator-TLQLTQIB.js → plugin-creator-ZCOZ3UCT.js} +1 -2
- package/dist/{registry-BQSPZS3F.js → registry-FBPEGL2T.js} +2 -3
- package/dist/templates/project-starter/package.json +4 -4
- package/dist/templates/project-tee-starter/package.json +3 -3
- package/dist/{utils-BROS5JZQ.js → utils-I3EA43DE.js} +6 -19
- package/package.json +8 -6
- package/templates/project-starter/package.json +4 -4
- package/templates/project-tee-starter/package.json +3 -3
- package/dist/assets/index-CYy-fwbh.js.br +0 -0
- package/dist/assets/index-DzLbKTxV.css +0 -1
- package/dist/assets/index-DzLbKTxV.css.br +0 -0
- package/dist/assets/index-TE3LspKB.js.br +0 -0
- package/dist/assets/vendor-DSdxb8P-.js.br +0 -0
- package/dist/chunk-RIAWNDYI.js +0 -49
- package/dist/migrator-UQ4XFYE5.js +0 -744
|
@@ -4,11 +4,9 @@ const require = createRequire(import.meta.url);
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
displayBunInstallationTipCompact,
|
|
7
|
+
emoji,
|
|
7
8
|
runBunCommand
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import {
|
|
10
|
-
emoji
|
|
11
|
-
} from "./chunk-KB3JDWUI.js";
|
|
9
|
+
} from "./chunk-W4NJVJQV.js";
|
|
12
10
|
import {
|
|
13
11
|
getAgentRuntimeUrl,
|
|
14
12
|
getAgentsBaseUrl
|
|
@@ -816,405 +814,16 @@ async function confirmAction(message) {
|
|
|
816
814
|
}
|
|
817
815
|
|
|
818
816
|
// src/utils/config-manager.ts
|
|
819
|
-
import path6 from "path";
|
|
820
|
-
import { promises as fs5 } from "fs";
|
|
821
|
-
import { logger as logger7 } from "@elizaos/core";
|
|
822
|
-
|
|
823
|
-
// src/utils/env-prompt.ts
|
|
824
|
-
import * as clack2 from "@clack/prompts";
|
|
825
|
-
import colors from "yoctocolors";
|
|
826
|
-
import { promises as fs4 } from "fs";
|
|
827
817
|
import path5 from "path";
|
|
818
|
+
import { promises as fs4 } from "fs";
|
|
828
819
|
import { logger as logger6 } from "@elizaos/core";
|
|
829
|
-
var ENV_VAR_CONFIGS = {
|
|
830
|
-
openai: [
|
|
831
|
-
{
|
|
832
|
-
name: "OpenAI API Key",
|
|
833
|
-
key: "OPENAI_API_KEY",
|
|
834
|
-
required: true,
|
|
835
|
-
description: "Required for the OpenAI plugin to generate text and embeddings.",
|
|
836
|
-
url: "https://platform.openai.com/api-keys",
|
|
837
|
-
secret: true
|
|
838
|
-
}
|
|
839
|
-
],
|
|
840
|
-
anthropic: [
|
|
841
|
-
{
|
|
842
|
-
name: "Anthropic API Key",
|
|
843
|
-
key: "ANTHROPIC_API_KEY",
|
|
844
|
-
required: true,
|
|
845
|
-
description: "Required for the Anthropic plugin to use Claude models.",
|
|
846
|
-
url: "https://console.anthropic.com/settings/keys",
|
|
847
|
-
secret: true
|
|
848
|
-
}
|
|
849
|
-
],
|
|
850
|
-
discord: [
|
|
851
|
-
{
|
|
852
|
-
name: "Discord API Token",
|
|
853
|
-
key: "DISCORD_API_TOKEN",
|
|
854
|
-
required: false,
|
|
855
|
-
description: "The bot token for your Discord application. This enables your agent to connect to Discord and interact with users there.",
|
|
856
|
-
url: "https://discord.com/developers/applications",
|
|
857
|
-
secret: true
|
|
858
|
-
},
|
|
859
|
-
{
|
|
860
|
-
name: "Discord Application ID",
|
|
861
|
-
key: "DISCORD_APPLICATION_ID",
|
|
862
|
-
required: false,
|
|
863
|
-
description: "The application ID for your Discord bot. Required together with the API token to enable Discord integration.",
|
|
864
|
-
url: "https://discord.com/developers/applications",
|
|
865
|
-
secret: false
|
|
866
|
-
}
|
|
867
|
-
],
|
|
868
|
-
twitter: [
|
|
869
|
-
{
|
|
870
|
-
name: "Twitter API Key",
|
|
871
|
-
key: "TWITTER_API_KEY",
|
|
872
|
-
required: false,
|
|
873
|
-
description: "API Key for Twitter integration. Needed to connect your agent to Twitter.",
|
|
874
|
-
url: "https://developer.twitter.com/en/portal/dashboard",
|
|
875
|
-
secret: true
|
|
876
|
-
},
|
|
877
|
-
{
|
|
878
|
-
name: "Twitter API Secret",
|
|
879
|
-
key: "TWITTER_API_SECRET",
|
|
880
|
-
required: false,
|
|
881
|
-
description: "API Secret for Twitter integration.",
|
|
882
|
-
url: "https://developer.twitter.com/en/portal/dashboard",
|
|
883
|
-
secret: true
|
|
884
|
-
},
|
|
885
|
-
{
|
|
886
|
-
name: "Twitter Access Token",
|
|
887
|
-
key: "TWITTER_ACCESS_TOKEN",
|
|
888
|
-
required: false,
|
|
889
|
-
description: "Access Token for Twitter integration.",
|
|
890
|
-
url: "https://developer.twitter.com/en/portal/dashboard",
|
|
891
|
-
secret: true
|
|
892
|
-
},
|
|
893
|
-
{
|
|
894
|
-
name: "Twitter Access Token Secret",
|
|
895
|
-
key: "TWITTER_ACCESS_TOKEN_SECRET",
|
|
896
|
-
required: false,
|
|
897
|
-
description: "Access Token Secret for Twitter integration.",
|
|
898
|
-
url: "https://developer.twitter.com/en/portal/dashboard",
|
|
899
|
-
secret: true
|
|
900
|
-
}
|
|
901
|
-
],
|
|
902
|
-
telegram: [
|
|
903
|
-
{
|
|
904
|
-
name: "Telegram Bot Token",
|
|
905
|
-
key: "TELEGRAM_BOT_TOKEN",
|
|
906
|
-
required: false,
|
|
907
|
-
description: "Bot Token for Telegram integration. Needed to connect your agent to Telegram.",
|
|
908
|
-
url: "https://core.telegram.org/bots#how-do-i-create-a-bot",
|
|
909
|
-
secret: true
|
|
910
|
-
}
|
|
911
|
-
],
|
|
912
|
-
pglite: [
|
|
913
|
-
{
|
|
914
|
-
name: "Database Directory",
|
|
915
|
-
key: "PGLITE_DATA_DIR",
|
|
916
|
-
required: false,
|
|
917
|
-
description: "Directory where PGLite will store database files.",
|
|
918
|
-
url: "",
|
|
919
|
-
secret: false
|
|
920
|
-
}
|
|
921
|
-
],
|
|
922
|
-
postgresql: [
|
|
923
|
-
{
|
|
924
|
-
name: "PostgreSQL URL",
|
|
925
|
-
key: "POSTGRES_URL",
|
|
926
|
-
required: false,
|
|
927
|
-
description: "URL for connecting to your PostgreSQL database.",
|
|
928
|
-
url: "https://neon.tech/docs/connect/connect-from-any-app",
|
|
929
|
-
secret: false
|
|
930
|
-
}
|
|
931
|
-
]
|
|
932
|
-
};
|
|
933
|
-
async function getEnvFilePath() {
|
|
934
|
-
const envInfo = await UserEnvironment.getInstanceInfo();
|
|
935
|
-
return envInfo.paths.envFilePath;
|
|
936
|
-
}
|
|
937
|
-
async function readEnvFile() {
|
|
938
|
-
const envPath = await getEnvFilePath();
|
|
939
|
-
const result = {};
|
|
940
|
-
try {
|
|
941
|
-
if (await fs4.access(envPath).then(() => true).catch(() => false)) {
|
|
942
|
-
const content = await fs4.readFile(envPath, "utf8");
|
|
943
|
-
const lines = content.split("\n");
|
|
944
|
-
for (const line of lines) {
|
|
945
|
-
const trimmedLine = line.trim();
|
|
946
|
-
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
947
|
-
const separatorIndex = trimmedLine.indexOf("=");
|
|
948
|
-
if (separatorIndex > 0) {
|
|
949
|
-
const key = trimmedLine.substring(0, separatorIndex).trim();
|
|
950
|
-
const value = trimmedLine.substring(separatorIndex + 1).trim();
|
|
951
|
-
result[key] = value;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
} catch (error) {
|
|
957
|
-
logger6.error(`Error reading environment file: ${error}`);
|
|
958
|
-
}
|
|
959
|
-
return result;
|
|
960
|
-
}
|
|
961
|
-
async function writeEnvFile(envVars) {
|
|
962
|
-
try {
|
|
963
|
-
const envPath = await getEnvFilePath();
|
|
964
|
-
const elizaDir = path5.dirname(envPath);
|
|
965
|
-
if (!await fs4.access(elizaDir).then(() => true).catch(() => false)) {
|
|
966
|
-
await fs4.mkdir(elizaDir, { recursive: true });
|
|
967
|
-
}
|
|
968
|
-
let content = "";
|
|
969
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
970
|
-
content += `${key}=${value}
|
|
971
|
-
`;
|
|
972
|
-
}
|
|
973
|
-
await fs4.writeFile(envPath, content, "utf8");
|
|
974
|
-
logger6.info(`Environment variables saved to ${envPath}`);
|
|
975
|
-
} catch (error) {
|
|
976
|
-
logger6.error(`Error writing environment file: ${error}`);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
async function promptForEnvVar(config) {
|
|
980
|
-
const existingValue = process.env[config.key];
|
|
981
|
-
if (existingValue && existingValue.trim() !== "") {
|
|
982
|
-
return existingValue;
|
|
983
|
-
}
|
|
984
|
-
console.log(
|
|
985
|
-
colors.magenta(
|
|
986
|
-
`
|
|
987
|
-
${config.name} ${config.required ? "(Required)" : "(Optional - press Enter to skip)"}`
|
|
988
|
-
)
|
|
989
|
-
);
|
|
990
|
-
console.log(colors.white(config.description));
|
|
991
|
-
if (config.url) {
|
|
992
|
-
console.log(colors.blue(`Get it here: ${config.url}`));
|
|
993
|
-
}
|
|
994
|
-
const value = await (config.secret ? clack2.password({
|
|
995
|
-
message: `Enter your ${config.name}:`,
|
|
996
|
-
validate: (input) => {
|
|
997
|
-
if (config.required && (!input || input.trim() === "")) {
|
|
998
|
-
return "This field is required";
|
|
999
|
-
}
|
|
1000
|
-
return void 0;
|
|
1001
|
-
}
|
|
1002
|
-
}) : clack2.text({
|
|
1003
|
-
message: `Enter your ${config.name}:`,
|
|
1004
|
-
validate: (input) => {
|
|
1005
|
-
if (config.required && (!input || input.trim() === "")) {
|
|
1006
|
-
return "This field is required";
|
|
1007
|
-
}
|
|
1008
|
-
return void 0;
|
|
1009
|
-
}
|
|
1010
|
-
}));
|
|
1011
|
-
if (clack2.isCancel(value)) {
|
|
1012
|
-
clack2.cancel("Operation cancelled.");
|
|
1013
|
-
process.exit(0);
|
|
1014
|
-
}
|
|
1015
|
-
if (!config.required && (!value || value.trim() === "")) {
|
|
1016
|
-
return "";
|
|
1017
|
-
}
|
|
1018
|
-
if (config.key === "PGLITE_DATA_DIR" && value && value.startsWith("~")) {
|
|
1019
|
-
return value.replace(/^~/, process.cwd());
|
|
1020
|
-
}
|
|
1021
|
-
return value;
|
|
1022
|
-
}
|
|
1023
|
-
async function promptForEnvVars(pluginName) {
|
|
1024
|
-
const envVarConfigs = ENV_VAR_CONFIGS[pluginName.toLowerCase()];
|
|
1025
|
-
if (!envVarConfigs) {
|
|
1026
|
-
return {};
|
|
1027
|
-
}
|
|
1028
|
-
if (pluginName.toLowerCase() === "discord") {
|
|
1029
|
-
console.log(colors.blue("\n=== Discord Integration (Optional) ==="));
|
|
1030
|
-
console.log(
|
|
1031
|
-
colors.white(
|
|
1032
|
-
"Setting up Discord integration will allow your agent to interact with Discord users."
|
|
1033
|
-
)
|
|
1034
|
-
);
|
|
1035
|
-
console.log(
|
|
1036
|
-
colors.white("You can press Enter to skip these if you don't want to use Discord.")
|
|
1037
|
-
);
|
|
1038
|
-
} else if (pluginName.toLowerCase() === "twitter") {
|
|
1039
|
-
console.log(colors.blue("\n=== Twitter Integration (Optional) ==="));
|
|
1040
|
-
console.log(
|
|
1041
|
-
colors.white(
|
|
1042
|
-
"Setting up Twitter integration will allow your agent to post and interact on Twitter."
|
|
1043
|
-
)
|
|
1044
|
-
);
|
|
1045
|
-
console.log(
|
|
1046
|
-
colors.white("You can press Enter to skip these if you don't want to use Twitter.")
|
|
1047
|
-
);
|
|
1048
|
-
} else if (pluginName.toLowerCase() === "telegram") {
|
|
1049
|
-
console.log(colors.blue("\n=== Telegram Integration (Optional) ==="));
|
|
1050
|
-
console.log(
|
|
1051
|
-
colors.white(
|
|
1052
|
-
"Setting up Telegram integration will allow your agent to interact in Telegram chats."
|
|
1053
|
-
)
|
|
1054
|
-
);
|
|
1055
|
-
console.log(
|
|
1056
|
-
colors.white("You can press Enter to skip these if you don't want to use Telegram.")
|
|
1057
|
-
);
|
|
1058
|
-
}
|
|
1059
|
-
const envVars = await readEnvFile();
|
|
1060
|
-
const result = {};
|
|
1061
|
-
let changes = false;
|
|
1062
|
-
for (const config of envVarConfigs) {
|
|
1063
|
-
if (envVars[config.key] && envVars[config.key] !== "dummy_key" && envVars[config.key] !== "invalid_token_for_testing") {
|
|
1064
|
-
continue;
|
|
1065
|
-
}
|
|
1066
|
-
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
1067
|
-
const value = await promptForEnvVar(config);
|
|
1068
|
-
if (value !== null) {
|
|
1069
|
-
result[config.key] = value;
|
|
1070
|
-
envVars[config.key] = value;
|
|
1071
|
-
process.env[config.key] = value;
|
|
1072
|
-
}
|
|
1073
|
-
changes = true;
|
|
1074
|
-
}
|
|
1075
|
-
if (changes) {
|
|
1076
|
-
writeEnvFile(envVars);
|
|
1077
|
-
}
|
|
1078
|
-
return result;
|
|
1079
|
-
}
|
|
1080
|
-
async function validateEnvVars(pluginName) {
|
|
1081
|
-
const envVarConfigs = ENV_VAR_CONFIGS[pluginName.toLowerCase()];
|
|
1082
|
-
if (!envVarConfigs) {
|
|
1083
|
-
return true;
|
|
1084
|
-
}
|
|
1085
|
-
const envVars = await readEnvFile();
|
|
1086
|
-
for (const config of envVarConfigs) {
|
|
1087
|
-
if (config.required && (!envVars[config.key] || envVars[config.key] === "dummy_key")) {
|
|
1088
|
-
return false;
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
return true;
|
|
1092
|
-
}
|
|
1093
|
-
async function getMissingEnvVars(pluginName) {
|
|
1094
|
-
const envVarConfigs = ENV_VAR_CONFIGS[pluginName.toLowerCase()];
|
|
1095
|
-
if (!envVarConfigs) {
|
|
1096
|
-
return [];
|
|
1097
|
-
}
|
|
1098
|
-
const envVars = await readEnvFile();
|
|
1099
|
-
const missing = [];
|
|
1100
|
-
for (const config of envVarConfigs) {
|
|
1101
|
-
if (config.required && (!envVars[config.key] || envVars[config.key] === "dummy_key")) {
|
|
1102
|
-
missing.push(config.key);
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
return missing;
|
|
1106
|
-
}
|
|
1107
|
-
async function validatePluginEnvVars(pluginName) {
|
|
1108
|
-
const envVars = await readEnvFile();
|
|
1109
|
-
switch (pluginName.toLowerCase()) {
|
|
1110
|
-
case "discord":
|
|
1111
|
-
if (envVars.DISCORD_API_TOKEN && envVars.DISCORD_API_TOKEN.trim() !== "" && (!envVars.DISCORD_APPLICATION_ID || envVars.DISCORD_APPLICATION_ID.trim() === "")) {
|
|
1112
|
-
return {
|
|
1113
|
-
valid: false,
|
|
1114
|
-
message: "Discord Application ID is required when using a Discord API Token"
|
|
1115
|
-
};
|
|
1116
|
-
}
|
|
1117
|
-
if (envVars.DISCORD_API_TOKEN && envVars.DISCORD_API_TOKEN.trim() !== "" && envVars.DISCORD_APPLICATION_ID && envVars.DISCORD_APPLICATION_ID.trim() !== "") {
|
|
1118
|
-
return {
|
|
1119
|
-
valid: true,
|
|
1120
|
-
message: "Discord integration is properly configured."
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1123
|
-
if ((!envVars.DISCORD_API_TOKEN || envVars.DISCORD_API_TOKEN.trim() === "") && (!envVars.DISCORD_APPLICATION_ID || envVars.DISCORD_APPLICATION_ID.trim() === "")) {
|
|
1124
|
-
return {
|
|
1125
|
-
valid: true,
|
|
1126
|
-
message: "Discord integration is not configured (optional)."
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
return {
|
|
1130
|
-
valid: false,
|
|
1131
|
-
message: "Discord configuration is incomplete. Please provide both API Token and Application ID."
|
|
1132
|
-
};
|
|
1133
|
-
case "twitter": {
|
|
1134
|
-
const twitterKeys = [
|
|
1135
|
-
"TWITTER_API_KEY",
|
|
1136
|
-
"TWITTER_API_SECRET",
|
|
1137
|
-
"TWITTER_ACCESS_TOKEN",
|
|
1138
|
-
"TWITTER_ACCESS_TOKEN_SECRET"
|
|
1139
|
-
];
|
|
1140
|
-
const providedKeys = twitterKeys.filter((key) => envVars[key] && envVars[key].trim() !== "");
|
|
1141
|
-
if (providedKeys.length > 0 && providedKeys.length < twitterKeys.length) {
|
|
1142
|
-
return {
|
|
1143
|
-
valid: false,
|
|
1144
|
-
message: `Twitter configuration is incomplete. Missing: ${twitterKeys.filter((key) => !providedKeys.includes(key)).join(", ")}`
|
|
1145
|
-
};
|
|
1146
|
-
}
|
|
1147
|
-
if (providedKeys.length === twitterKeys.length) {
|
|
1148
|
-
return {
|
|
1149
|
-
valid: true,
|
|
1150
|
-
message: "Twitter configuration is valid"
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
return {
|
|
1154
|
-
valid: true,
|
|
1155
|
-
message: "Twitter integration is not configured (optional)."
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
case "telegram":
|
|
1159
|
-
if (envVars.TELEGRAM_BOT_TOKEN && envVars.TELEGRAM_BOT_TOKEN.trim() !== "") {
|
|
1160
|
-
return {
|
|
1161
|
-
valid: true,
|
|
1162
|
-
message: "Telegram configuration is valid"
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
return {
|
|
1166
|
-
valid: false,
|
|
1167
|
-
message: "Telegram Bot Token is required for Telegram integration"
|
|
1168
|
-
};
|
|
1169
|
-
case "openai":
|
|
1170
|
-
if (envVars.OPENAI_API_KEY && envVars.OPENAI_API_KEY.trim() !== "") {
|
|
1171
|
-
return {
|
|
1172
|
-
valid: true,
|
|
1173
|
-
message: "OpenAI configuration is valid"
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
return {
|
|
1177
|
-
valid: false,
|
|
1178
|
-
message: "OpenAI API Key is required for OpenAI integration"
|
|
1179
|
-
};
|
|
1180
|
-
case "anthropic":
|
|
1181
|
-
if (envVars.ANTHROPIC_API_KEY && envVars.ANTHROPIC_API_KEY.trim() !== "") {
|
|
1182
|
-
return {
|
|
1183
|
-
valid: true,
|
|
1184
|
-
message: "Anthropic configuration is valid"
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
return {
|
|
1188
|
-
valid: false,
|
|
1189
|
-
message: "Anthropic API Key is required for Anthropic integration"
|
|
1190
|
-
};
|
|
1191
|
-
case "postgres":
|
|
1192
|
-
if (envVars.POSTGRES_URL && envVars.POSTGRES_URL.trim() !== "") {
|
|
1193
|
-
return {
|
|
1194
|
-
valid: true,
|
|
1195
|
-
message: "PostgreSQL configuration is valid"
|
|
1196
|
-
};
|
|
1197
|
-
}
|
|
1198
|
-
return {
|
|
1199
|
-
valid: false,
|
|
1200
|
-
message: "PostgreSQL URL is required for PostgreSQL integration"
|
|
1201
|
-
};
|
|
1202
|
-
default:
|
|
1203
|
-
return {
|
|
1204
|
-
valid: true,
|
|
1205
|
-
message: `No specific validation rules for ${pluginName}`
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
// src/utils/config-manager.ts
|
|
1211
820
|
async function getConfigFilePath() {
|
|
1212
821
|
const envInfo = await UserEnvironment.getInstanceInfo();
|
|
1213
822
|
return envInfo.paths.configPath;
|
|
1214
823
|
}
|
|
1215
824
|
async function fileExists(p) {
|
|
1216
825
|
try {
|
|
1217
|
-
await
|
|
826
|
+
await fs4.access(p);
|
|
1218
827
|
return true;
|
|
1219
828
|
} catch {
|
|
1220
829
|
return false;
|
|
@@ -1230,10 +839,10 @@ async function loadConfig() {
|
|
|
1230
839
|
// Mark as default config
|
|
1231
840
|
};
|
|
1232
841
|
}
|
|
1233
|
-
const content = await
|
|
842
|
+
const content = await fs4.readFile(configPath, "utf8");
|
|
1234
843
|
return JSON.parse(content);
|
|
1235
844
|
} catch (error) {
|
|
1236
|
-
|
|
845
|
+
logger6.warn(`Error loading configuration: ${error}`);
|
|
1237
846
|
return {
|
|
1238
847
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1239
848
|
isDefault: true
|
|
@@ -1244,53 +853,31 @@ async function loadConfig() {
|
|
|
1244
853
|
async function saveConfig(config) {
|
|
1245
854
|
try {
|
|
1246
855
|
const configPath = await getConfigFilePath();
|
|
1247
|
-
const elizaDir =
|
|
856
|
+
const elizaDir = path5.dirname(configPath);
|
|
1248
857
|
if (!await fileExists(elizaDir)) {
|
|
1249
|
-
await
|
|
858
|
+
await fs4.mkdir(elizaDir, { recursive: true });
|
|
1250
859
|
}
|
|
1251
860
|
config.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
1252
|
-
await
|
|
1253
|
-
|
|
861
|
+
await fs4.writeFile(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
862
|
+
logger6.info(`Configuration saved to ${configPath}`);
|
|
1254
863
|
} catch (error) {
|
|
1255
|
-
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
async function checkPluginRequirements(pluginName) {
|
|
1259
|
-
return validatePluginEnvVars(pluginName);
|
|
1260
|
-
}
|
|
1261
|
-
async function getPluginStatus() {
|
|
1262
|
-
const configPath = await getConfigFilePath();
|
|
1263
|
-
if (!await fileExists(configPath)) {
|
|
1264
|
-
return {};
|
|
1265
|
-
}
|
|
1266
|
-
try {
|
|
1267
|
-
const configContent = await fs5.readFile(configPath, "utf-8");
|
|
1268
|
-
const config = JSON.parse(configContent);
|
|
1269
|
-
const status = {};
|
|
1270
|
-
for (const plugin of Object.keys(config.plugins ?? {})) {
|
|
1271
|
-
const check = await validatePluginEnvVars(plugin);
|
|
1272
|
-
status[plugin] = check.valid;
|
|
1273
|
-
}
|
|
1274
|
-
return status;
|
|
1275
|
-
} catch (error) {
|
|
1276
|
-
logger7.error(`Error reading config file: ${error}`);
|
|
1277
|
-
return {};
|
|
864
|
+
logger6.error(`Error saving configuration: ${error}`);
|
|
1278
865
|
}
|
|
1279
866
|
}
|
|
1280
867
|
|
|
1281
868
|
// src/utils/copy-template.ts
|
|
1282
869
|
import { existsSync as existsSync5 } from "fs";
|
|
1283
|
-
import { promises as
|
|
1284
|
-
import
|
|
870
|
+
import { promises as fs5 } from "fs";
|
|
871
|
+
import path6 from "path";
|
|
1285
872
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1286
|
-
import { logger as
|
|
873
|
+
import { logger as logger7 } from "@elizaos/core";
|
|
1287
874
|
var __filename = fileURLToPath2(import.meta.url);
|
|
1288
|
-
var __dirname =
|
|
875
|
+
var __dirname = path6.dirname(__filename);
|
|
1289
876
|
async function copyDir(src, dest, exclude = []) {
|
|
1290
|
-
const resolvedSrc =
|
|
1291
|
-
const resolvedDest =
|
|
1292
|
-
await
|
|
1293
|
-
const entries = await
|
|
877
|
+
const resolvedSrc = path6.resolve(src);
|
|
878
|
+
const resolvedDest = path6.resolve(dest);
|
|
879
|
+
await fs5.mkdir(resolvedDest, { recursive: true });
|
|
880
|
+
const entries = await fs5.readdir(resolvedSrc, { withFileTypes: true });
|
|
1294
881
|
const files = [];
|
|
1295
882
|
const directories = [];
|
|
1296
883
|
for (const entry of entries) {
|
|
@@ -1311,16 +898,16 @@ async function copyDir(src, dest, exclude = []) {
|
|
|
1311
898
|
for (let i = 0; i < files.length; i += MAX_CONCURRENT_FILES) {
|
|
1312
899
|
const batch = files.slice(i, i + MAX_CONCURRENT_FILES);
|
|
1313
900
|
const batchPromises = batch.map(async (entry) => {
|
|
1314
|
-
const srcPath =
|
|
1315
|
-
const destPath =
|
|
1316
|
-
await
|
|
901
|
+
const srcPath = path6.join(resolvedSrc, entry.name);
|
|
902
|
+
const destPath = path6.join(resolvedDest, entry.name);
|
|
903
|
+
await fs5.copyFile(srcPath, destPath);
|
|
1317
904
|
});
|
|
1318
905
|
filePromises.push(...batchPromises);
|
|
1319
906
|
}
|
|
1320
907
|
await Promise.all(filePromises);
|
|
1321
908
|
for (const entry of directories) {
|
|
1322
|
-
const srcPath =
|
|
1323
|
-
const destPath =
|
|
909
|
+
const srcPath = path6.join(resolvedSrc, entry.name);
|
|
910
|
+
const destPath = path6.join(resolvedDest, entry.name);
|
|
1324
911
|
await copyDir(srcPath, destPath, exclude);
|
|
1325
912
|
}
|
|
1326
913
|
}
|
|
@@ -1340,24 +927,24 @@ async function copyTemplate(templateType, targetDir) {
|
|
|
1340
927
|
const packageName = getPackageName(templateType);
|
|
1341
928
|
const possibleTemplatePaths = [
|
|
1342
929
|
// 1. Direct path from source directory (for tests and development)
|
|
1343
|
-
|
|
930
|
+
path6.resolve(__dirname, "../../templates", packageName),
|
|
1344
931
|
// 2. Production: templates bundled with the CLI dist
|
|
1345
|
-
|
|
1346
|
-
|
|
932
|
+
path6.resolve(
|
|
933
|
+
path6.dirname(__require.resolve("@elizaos/cli/package.json")),
|
|
1347
934
|
"dist",
|
|
1348
935
|
"templates",
|
|
1349
936
|
packageName
|
|
1350
937
|
),
|
|
1351
938
|
// 3. Development/Test: templates in the CLI package root
|
|
1352
|
-
|
|
1353
|
-
|
|
939
|
+
path6.resolve(
|
|
940
|
+
path6.dirname(__require.resolve("@elizaos/cli/package.json")),
|
|
1354
941
|
"templates",
|
|
1355
942
|
packageName
|
|
1356
943
|
),
|
|
1357
944
|
// 4. Fallback: relative to current module (for built dist)
|
|
1358
|
-
|
|
945
|
+
path6.resolve(__dirname, "..", "templates", packageName),
|
|
1359
946
|
// 5. Additional fallback: relative to dist directory
|
|
1360
|
-
|
|
947
|
+
path6.resolve(__dirname, "..", "..", "templates", packageName)
|
|
1361
948
|
];
|
|
1362
949
|
let templateDir = null;
|
|
1363
950
|
for (const possiblePath of possibleTemplatePaths) {
|
|
@@ -1372,29 +959,29 @@ async function copyTemplate(templateType, targetDir) {
|
|
|
1372
959
|
${possibleTemplatePaths.join("\n")}`
|
|
1373
960
|
);
|
|
1374
961
|
}
|
|
1375
|
-
|
|
962
|
+
logger7.debug(`Copying ${templateType} template from ${templateDir} to ${targetDir}`);
|
|
1376
963
|
await copyDir(templateDir, targetDir);
|
|
1377
964
|
if (templateType === "plugin") {
|
|
1378
|
-
const pluginNameFromPath =
|
|
965
|
+
const pluginNameFromPath = path6.basename(targetDir);
|
|
1379
966
|
await replacePluginNameInFiles(targetDir, pluginNameFromPath);
|
|
1380
967
|
}
|
|
1381
|
-
const packageJsonPath =
|
|
968
|
+
const packageJsonPath = path6.join(targetDir, "package.json");
|
|
1382
969
|
try {
|
|
1383
|
-
const cliPackageJsonPath =
|
|
1384
|
-
|
|
970
|
+
const cliPackageJsonPath = path6.resolve(
|
|
971
|
+
path6.dirname(__require.resolve("@elizaos/cli/package.json")),
|
|
1385
972
|
"package.json"
|
|
1386
973
|
);
|
|
1387
|
-
const cliPackageJson = JSON.parse(await
|
|
974
|
+
const cliPackageJson = JSON.parse(await fs5.readFile(cliPackageJsonPath, "utf8"));
|
|
1388
975
|
const cliPackageVersion = cliPackageJson.version;
|
|
1389
|
-
const packageJson = JSON.parse(await
|
|
976
|
+
const packageJson = JSON.parse(await fs5.readFile(packageJsonPath, "utf8"));
|
|
1390
977
|
if (packageJson.private) {
|
|
1391
978
|
delete packageJson.private;
|
|
1392
|
-
|
|
979
|
+
logger7.debug("Removed private field from template package.json");
|
|
1393
980
|
}
|
|
1394
981
|
if (packageJson.dependencies) {
|
|
1395
982
|
for (const depName of Object.keys(packageJson.dependencies)) {
|
|
1396
983
|
if (depName.startsWith("@elizaos/")) {
|
|
1397
|
-
|
|
984
|
+
logger7.info(`Setting ${depName} to use version ${cliPackageVersion}`);
|
|
1398
985
|
packageJson.dependencies[depName] = "latest";
|
|
1399
986
|
}
|
|
1400
987
|
}
|
|
@@ -1402,22 +989,22 @@ ${possibleTemplatePaths.join("\n")}`
|
|
|
1402
989
|
if (packageJson.devDependencies) {
|
|
1403
990
|
for (const depName of Object.keys(packageJson.devDependencies)) {
|
|
1404
991
|
if (depName.startsWith("@elizaos/")) {
|
|
1405
|
-
|
|
992
|
+
logger7.info(`Setting dev dependency ${depName} to use version ${cliPackageVersion}`);
|
|
1406
993
|
packageJson.devDependencies[depName] = "latest";
|
|
1407
994
|
}
|
|
1408
995
|
}
|
|
1409
996
|
}
|
|
1410
|
-
const projectNameFromPath =
|
|
997
|
+
const projectNameFromPath = path6.basename(targetDir);
|
|
1411
998
|
if (packageJson.name !== projectNameFromPath) {
|
|
1412
999
|
packageJson.name = projectNameFromPath;
|
|
1413
|
-
|
|
1000
|
+
logger7.info(`Setting package name to ${projectNameFromPath}`);
|
|
1414
1001
|
}
|
|
1415
|
-
await
|
|
1416
|
-
|
|
1002
|
+
await fs5.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
1003
|
+
logger7.debug("Updated package.json with latest dependency versions");
|
|
1417
1004
|
} catch (error) {
|
|
1418
|
-
|
|
1005
|
+
logger7.error(`Error updating package.json: ${error}`);
|
|
1419
1006
|
}
|
|
1420
|
-
|
|
1007
|
+
logger7.debug(`${templateType} template copied successfully`);
|
|
1421
1008
|
}
|
|
1422
1009
|
async function replacePluginNameInFiles(targetDir, pluginName) {
|
|
1423
1010
|
const filesToProcess = [
|
|
@@ -1428,16 +1015,16 @@ async function replacePluginNameInFiles(targetDir, pluginName) {
|
|
|
1428
1015
|
// package.json name is handled by the publish command
|
|
1429
1016
|
];
|
|
1430
1017
|
const promises2 = filesToProcess.map(async (filePath) => {
|
|
1431
|
-
const fullPath =
|
|
1018
|
+
const fullPath = path6.join(targetDir, filePath);
|
|
1432
1019
|
try {
|
|
1433
|
-
if (await
|
|
1434
|
-
let content = await
|
|
1020
|
+
if (await fs5.access(fullPath).then(() => true).catch(() => false)) {
|
|
1021
|
+
let content = await fs5.readFile(fullPath, "utf8");
|
|
1435
1022
|
content = content.replace(/plugin-starter/g, pluginName);
|
|
1436
|
-
await
|
|
1437
|
-
|
|
1023
|
+
await fs5.writeFile(fullPath, content, "utf8");
|
|
1024
|
+
logger7.debug(`Updated plugin name in ${filePath}`);
|
|
1438
1025
|
}
|
|
1439
1026
|
} catch (error) {
|
|
1440
|
-
|
|
1027
|
+
logger7.warn(
|
|
1441
1028
|
`Could not update ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
1442
1029
|
);
|
|
1443
1030
|
}
|
|
@@ -1445,12 +1032,12 @@ async function replacePluginNameInFiles(targetDir, pluginName) {
|
|
|
1445
1032
|
await Promise.all(promises2);
|
|
1446
1033
|
}
|
|
1447
1034
|
async function copyClientDist() {
|
|
1448
|
-
|
|
1449
|
-
const srcClientDist =
|
|
1450
|
-
const destClientDist =
|
|
1451
|
-
const indexSrc =
|
|
1452
|
-
const indexDest =
|
|
1453
|
-
await
|
|
1035
|
+
logger7.debug("Copying client dist files to CLI package");
|
|
1036
|
+
const srcClientDist = path6.resolve(process.cwd(), "../client/dist");
|
|
1037
|
+
const destClientDist = path6.resolve(process.cwd(), "./dist");
|
|
1038
|
+
const indexSrc = path6.join(srcClientDist, "index.html");
|
|
1039
|
+
const indexDest = path6.join(destClientDist, "index.html");
|
|
1040
|
+
await fs5.mkdir(destClientDist, { recursive: true });
|
|
1454
1041
|
let retries = 0;
|
|
1455
1042
|
const maxRetries = 10;
|
|
1456
1043
|
const retryDelay = 1e3;
|
|
@@ -1458,33 +1045,45 @@ async function copyClientDist() {
|
|
|
1458
1045
|
if (existsSync5(indexSrc)) {
|
|
1459
1046
|
break;
|
|
1460
1047
|
}
|
|
1461
|
-
|
|
1048
|
+
logger7.info(`Waiting for client index.html (attempt ${retries + 1}/${maxRetries})\u2026`);
|
|
1462
1049
|
await new Promise((r) => setTimeout(r, retryDelay));
|
|
1463
1050
|
retries++;
|
|
1464
1051
|
}
|
|
1465
1052
|
if (!existsSync5(indexSrc)) {
|
|
1466
|
-
|
|
1467
|
-
|
|
1053
|
+
logger7.error(`index.html not found at ${indexSrc} after ${maxRetries} attempts`);
|
|
1054
|
+
logger7.error("Client package must be built before CLI package. Run: bun run build:client");
|
|
1468
1055
|
throw new Error("Client dist files not found - build the client package first");
|
|
1469
1056
|
}
|
|
1470
1057
|
await copyDir(srcClientDist, destClientDist);
|
|
1471
1058
|
if (!existsSync5(indexDest)) {
|
|
1472
|
-
|
|
1059
|
+
logger7.error(`index.html missing in CLI dist at ${indexDest}`);
|
|
1473
1060
|
throw new Error("Failed to copy client files to CLI dist directory");
|
|
1474
1061
|
}
|
|
1475
|
-
|
|
1476
|
-
|
|
1062
|
+
logger7.info("\u2705 Client files successfully copied to CLI package");
|
|
1063
|
+
logger7.success("Client dist files copied successfully");
|
|
1477
1064
|
}
|
|
1478
1065
|
|
|
1479
1066
|
// src/utils/display-banner.ts
|
|
1480
1067
|
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
1481
|
-
import
|
|
1068
|
+
import path7, { dirname } from "path";
|
|
1482
1069
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1483
1070
|
import { execa as execa4 } from "execa";
|
|
1071
|
+
function isRunningFromNodeModules() {
|
|
1072
|
+
const __filename2 = fileURLToPath3(import.meta.url);
|
|
1073
|
+
return __filename2.includes("node_modules");
|
|
1074
|
+
}
|
|
1484
1075
|
function getVersion() {
|
|
1076
|
+
const userEnv = UserEnvironment.getInstance();
|
|
1077
|
+
const monorepoRoot = userEnv.findMonorepoRoot(process.cwd());
|
|
1078
|
+
if (monorepoRoot) {
|
|
1079
|
+
return "monorepo";
|
|
1080
|
+
}
|
|
1081
|
+
if (!isRunningFromNodeModules()) {
|
|
1082
|
+
return "monorepo";
|
|
1083
|
+
}
|
|
1485
1084
|
const __filename2 = fileURLToPath3(import.meta.url);
|
|
1486
1085
|
const __dirname2 = dirname(__filename2);
|
|
1487
|
-
const packageJsonPath =
|
|
1086
|
+
const packageJsonPath = path7.resolve(__dirname2, "../package.json");
|
|
1488
1087
|
let version = "0.0.0";
|
|
1489
1088
|
if (!existsSync6(packageJsonPath)) {
|
|
1490
1089
|
console.error(`Warning: package.json not found at ${packageJsonPath}`);
|
|
@@ -1519,6 +1118,9 @@ function isUtf8Locale() {
|
|
|
1519
1118
|
var versionCheckCache = null;
|
|
1520
1119
|
var CACHE_DURATION = 10 * 60 * 1e3;
|
|
1521
1120
|
async function getLatestCliVersion(currentVersion) {
|
|
1121
|
+
if (currentVersion === "monorepo") {
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1522
1124
|
try {
|
|
1523
1125
|
if (versionCheckCache && Date.now() - versionCheckCache.timestamp < CACHE_DURATION) {
|
|
1524
1126
|
return versionCheckCache.latestVersion;
|
|
@@ -1566,6 +1168,9 @@ function showUpdateNotification(currentVersion, latestVersion) {
|
|
|
1566
1168
|
console.log("");
|
|
1567
1169
|
}
|
|
1568
1170
|
async function checkAndShowUpdateNotification(currentVersion) {
|
|
1171
|
+
if (currentVersion === "monorepo") {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1569
1174
|
try {
|
|
1570
1175
|
const latestVersion = await getLatestCliVersion(currentVersion);
|
|
1571
1176
|
if (latestVersion) {
|
|
@@ -1648,12 +1253,275 @@ ${b}\u2800\u2800\u2800\u2800\u28B8\u28FF\u2866\u2800\u2800\u2809\u281B\u283F\u28
|
|
|
1648
1253
|
}
|
|
1649
1254
|
}
|
|
1650
1255
|
|
|
1256
|
+
// src/services/env-file.service.ts
|
|
1257
|
+
import { promises as fs6 } from "fs";
|
|
1258
|
+
import path8 from "path";
|
|
1259
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1260
|
+
import { logger as logger8 } from "@elizaos/core";
|
|
1261
|
+
var EnvFileService = class {
|
|
1262
|
+
filePath;
|
|
1263
|
+
constructor(filePath) {
|
|
1264
|
+
this.filePath = filePath || "";
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Initialize the service with the appropriate file path
|
|
1268
|
+
*/
|
|
1269
|
+
async initialize() {
|
|
1270
|
+
if (!this.filePath) {
|
|
1271
|
+
const envInfo = await UserEnvironment.getInstanceInfo();
|
|
1272
|
+
this.filePath = envInfo.paths.envFilePath;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Get the current environment file path
|
|
1277
|
+
*/
|
|
1278
|
+
getFilePath() {
|
|
1279
|
+
return this.filePath;
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Read and parse the environment file
|
|
1283
|
+
*/
|
|
1284
|
+
async read() {
|
|
1285
|
+
const result = {};
|
|
1286
|
+
try {
|
|
1287
|
+
if (!existsSync7(this.filePath)) {
|
|
1288
|
+
return result;
|
|
1289
|
+
}
|
|
1290
|
+
const content = await fs6.readFile(this.filePath, "utf-8");
|
|
1291
|
+
const lines = content.split("\n");
|
|
1292
|
+
for (const line of lines) {
|
|
1293
|
+
const trimmedLine = line.trim();
|
|
1294
|
+
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
1295
|
+
const separatorIndex = trimmedLine.indexOf("=");
|
|
1296
|
+
if (separatorIndex > 0) {
|
|
1297
|
+
const key = trimmedLine.substring(0, separatorIndex).trim();
|
|
1298
|
+
const value = trimmedLine.substring(separatorIndex + 1).trim();
|
|
1299
|
+
result[key] = value;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
} catch (error) {
|
|
1304
|
+
logger8.error(`Error reading environment file: ${error}`);
|
|
1305
|
+
}
|
|
1306
|
+
return result;
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Read environment file with comments preserved
|
|
1310
|
+
*/
|
|
1311
|
+
async readWithComments() {
|
|
1312
|
+
const entries = [];
|
|
1313
|
+
try {
|
|
1314
|
+
if (!existsSync7(this.filePath)) {
|
|
1315
|
+
return entries;
|
|
1316
|
+
}
|
|
1317
|
+
const content = await fs6.readFile(this.filePath, "utf-8");
|
|
1318
|
+
const lines = content.split("\n");
|
|
1319
|
+
let currentComment;
|
|
1320
|
+
for (const line of lines) {
|
|
1321
|
+
const trimmedLine = line.trim();
|
|
1322
|
+
if (trimmedLine.startsWith("#")) {
|
|
1323
|
+
const comment = trimmedLine.substring(1).trim();
|
|
1324
|
+
currentComment = currentComment ? `${currentComment}
|
|
1325
|
+
${comment}` : comment;
|
|
1326
|
+
} else if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
1327
|
+
const separatorIndex = trimmedLine.indexOf("=");
|
|
1328
|
+
if (separatorIndex > 0) {
|
|
1329
|
+
const key = trimmedLine.substring(0, separatorIndex).trim();
|
|
1330
|
+
const value = trimmedLine.substring(separatorIndex + 1).trim();
|
|
1331
|
+
entries.push({
|
|
1332
|
+
key,
|
|
1333
|
+
value,
|
|
1334
|
+
comment: currentComment
|
|
1335
|
+
});
|
|
1336
|
+
currentComment = void 0;
|
|
1337
|
+
}
|
|
1338
|
+
} else if (!trimmedLine) {
|
|
1339
|
+
currentComment = void 0;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
} catch (error) {
|
|
1343
|
+
logger8.error(`Error reading environment file with comments: ${error}`);
|
|
1344
|
+
}
|
|
1345
|
+
return entries;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Write environment variables to file
|
|
1349
|
+
*/
|
|
1350
|
+
async write(vars, options = {}) {
|
|
1351
|
+
const { preserveComments = false, createBackup = false, updateProcessEnv = true } = options;
|
|
1352
|
+
try {
|
|
1353
|
+
const dir = path8.dirname(this.filePath);
|
|
1354
|
+
if (!existsSync7(dir)) {
|
|
1355
|
+
await fs6.mkdir(dir, { recursive: true });
|
|
1356
|
+
}
|
|
1357
|
+
if (createBackup && existsSync7(this.filePath)) {
|
|
1358
|
+
const backupPath = `${this.filePath}.${Date.now()}.bak`;
|
|
1359
|
+
await fs6.copyFile(this.filePath, backupPath);
|
|
1360
|
+
logger8.info(`Created backup at ${backupPath}`);
|
|
1361
|
+
}
|
|
1362
|
+
let content = "";
|
|
1363
|
+
const varsCopy = { ...vars };
|
|
1364
|
+
if (preserveComments) {
|
|
1365
|
+
const existingEntries = await this.readWithComments();
|
|
1366
|
+
const existingKeys = new Set(existingEntries.map((e) => e.key));
|
|
1367
|
+
for (const entry of existingEntries) {
|
|
1368
|
+
if (Object.prototype.hasOwnProperty.call(varsCopy, entry.key)) {
|
|
1369
|
+
if (entry.comment) {
|
|
1370
|
+
content += `# ${entry.comment.replace(/\n/g, "\n# ")}
|
|
1371
|
+
`;
|
|
1372
|
+
}
|
|
1373
|
+
content += `${entry.key}=${varsCopy[entry.key]}
|
|
1374
|
+
`;
|
|
1375
|
+
delete varsCopy[entry.key];
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
if (Object.keys(varsCopy).length > 0 && content) {
|
|
1379
|
+
content += "\n";
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
for (const [key, value] of Object.entries(varsCopy)) {
|
|
1383
|
+
if (typeof value === "string") {
|
|
1384
|
+
content += `${key}=${value}
|
|
1385
|
+
`;
|
|
1386
|
+
if (updateProcessEnv) {
|
|
1387
|
+
process.env[key] = value;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
await fs6.writeFile(this.filePath, content, "utf-8");
|
|
1392
|
+
logger8.info(`Environment variables saved to ${this.filePath}`);
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
logger8.error(`Error writing environment file: ${error}`);
|
|
1395
|
+
throw error;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Update a single environment variable
|
|
1400
|
+
*/
|
|
1401
|
+
async update(key, value, options = {}) {
|
|
1402
|
+
const vars = await this.read();
|
|
1403
|
+
vars[key] = value;
|
|
1404
|
+
if (options.updateProcessEnv !== false) {
|
|
1405
|
+
process.env[key] = value;
|
|
1406
|
+
}
|
|
1407
|
+
await this.write(vars, { preserveComments: true, ...options });
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Update multiple environment variables
|
|
1411
|
+
*/
|
|
1412
|
+
async updateMany(updates, options = {}) {
|
|
1413
|
+
const vars = await this.read();
|
|
1414
|
+
Object.assign(vars, updates);
|
|
1415
|
+
if (options.updateProcessEnv !== false) {
|
|
1416
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
1417
|
+
process.env[key] = value;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
await this.write(vars, { preserveComments: true, ...options });
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Delete an environment variable
|
|
1424
|
+
*/
|
|
1425
|
+
async delete(key) {
|
|
1426
|
+
const vars = await this.read();
|
|
1427
|
+
delete vars[key];
|
|
1428
|
+
delete process.env[key];
|
|
1429
|
+
await this.write(vars, { preserveComments: true });
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Check if a key exists
|
|
1433
|
+
*/
|
|
1434
|
+
async exists(key) {
|
|
1435
|
+
const vars = await this.read();
|
|
1436
|
+
return Object.prototype.hasOwnProperty.call(vars, key);
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Get a single environment variable value
|
|
1440
|
+
*/
|
|
1441
|
+
async get(key) {
|
|
1442
|
+
const vars = await this.read();
|
|
1443
|
+
return vars[key];
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* Create a backup of the current environment file
|
|
1447
|
+
*/
|
|
1448
|
+
async backup() {
|
|
1449
|
+
if (!existsSync7(this.filePath)) {
|
|
1450
|
+
throw new Error("No environment file to backup");
|
|
1451
|
+
}
|
|
1452
|
+
const backupPath = `${this.filePath}.${Date.now()}.bak`;
|
|
1453
|
+
await fs6.copyFile(this.filePath, backupPath);
|
|
1454
|
+
return backupPath;
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Validate the environment file
|
|
1458
|
+
*/
|
|
1459
|
+
async validate() {
|
|
1460
|
+
const errors = [];
|
|
1461
|
+
try {
|
|
1462
|
+
if (!existsSync7(this.filePath)) {
|
|
1463
|
+
return { valid: true, errors: [] };
|
|
1464
|
+
}
|
|
1465
|
+
const content = await fs6.readFile(this.filePath, "utf-8");
|
|
1466
|
+
const lines = content.split("\n");
|
|
1467
|
+
lines.forEach((line, index) => {
|
|
1468
|
+
const trimmedLine = line.trim();
|
|
1469
|
+
if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
1470
|
+
const separatorIndex = trimmedLine.indexOf("=");
|
|
1471
|
+
if (separatorIndex < 1) {
|
|
1472
|
+
errors.push(`Line ${index + 1}: Invalid format (missing '=' separator)`);
|
|
1473
|
+
} else {
|
|
1474
|
+
const key = trimmedLine.substring(0, separatorIndex).trim();
|
|
1475
|
+
if (!/^[A-Z_][A-Z0-9_]*$/i.test(key)) {
|
|
1476
|
+
errors.push(`Line ${index + 1}: Invalid key format '${key}'`);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
} catch (error) {
|
|
1482
|
+
errors.push(`Error reading file: ${error}`);
|
|
1483
|
+
}
|
|
1484
|
+
return {
|
|
1485
|
+
valid: errors.length === 0,
|
|
1486
|
+
errors
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
var globalInstance = null;
|
|
1491
|
+
async function getEnvFileService() {
|
|
1492
|
+
if (!globalInstance) {
|
|
1493
|
+
globalInstance = new EnvFileService();
|
|
1494
|
+
await globalInstance.initialize();
|
|
1495
|
+
}
|
|
1496
|
+
return globalInstance;
|
|
1497
|
+
}
|
|
1498
|
+
function createEnvFileService(filePath) {
|
|
1499
|
+
return new EnvFileService(filePath);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// src/utils/env-prompt.ts
|
|
1503
|
+
async function getEnvFilePath() {
|
|
1504
|
+
const service = await getEnvFileService();
|
|
1505
|
+
return service.getFilePath();
|
|
1506
|
+
}
|
|
1507
|
+
async function readEnvFile() {
|
|
1508
|
+
const service = await getEnvFileService();
|
|
1509
|
+
return service.read();
|
|
1510
|
+
}
|
|
1511
|
+
async function writeEnvFile(envVars) {
|
|
1512
|
+
const service = await getEnvFileService();
|
|
1513
|
+
await service.write(envVars, {
|
|
1514
|
+
preserveComments: false,
|
|
1515
|
+
updateProcessEnv: true
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1651
1519
|
// src/utils/get-config.ts
|
|
1652
1520
|
import { logger as logger9 } from "@elizaos/core";
|
|
1653
1521
|
import dotenv2 from "dotenv";
|
|
1654
1522
|
import path9 from "path";
|
|
1655
|
-
import { existsSync as
|
|
1656
|
-
import * as
|
|
1523
|
+
import { existsSync as existsSync8, promises as fs7 } from "fs";
|
|
1524
|
+
import * as clack2 from "@clack/prompts";
|
|
1657
1525
|
import { z } from "zod";
|
|
1658
1526
|
var postgresConfigSchema = z.object({
|
|
1659
1527
|
type: z.literal("postgres"),
|
|
@@ -1671,19 +1539,19 @@ var SAMPLE_ENV_TEMPLATE = `### elizaOS Environment Variables ###
|
|
|
1671
1539
|
# To get started, copy this file to .env, or make a .env and add the settings you'd like to override
|
|
1672
1540
|
# Please read the comments for each of the configurations
|
|
1673
1541
|
|
|
1674
|
-
## The only thing you ABSOLUTELY NEED to get up and running is one of the model provider keys,
|
|
1542
|
+
## The only thing you ABSOLUTELY NEED to get up and running is one of the model provider keys,
|
|
1675
1543
|
## i.e. OPENAI_API_KEY or ANTHROPIC_API_KEY, or setup the local-ai or ollama plugin
|
|
1676
1544
|
## Everything else is optional, and most settings and secrets can be configured in your agent or through the GUI
|
|
1677
1545
|
## For multi-agent, each agent will need keys for the various services it is connected to
|
|
1678
1546
|
-------------------------------
|
|
1679
|
-
## You can use the .env or environment variables generally for shared keys, such as to model providers,
|
|
1547
|
+
## You can use the .env or environment variables generally for shared keys, such as to model providers,
|
|
1680
1548
|
## database, etc, with scoped keys for services such as Telegram, Discord, etc
|
|
1681
1549
|
|
|
1682
1550
|
## MODEL PROVIDER KEYS ##
|
|
1683
|
-
## Eliza is compatible with a wide array of model providers. Many have OpenAI compatible APIs,
|
|
1551
|
+
## Eliza is compatible with a wide array of model providers. Many have OpenAI compatible APIs,
|
|
1684
1552
|
## and you can use them by overriding the base URL
|
|
1685
1553
|
|
|
1686
|
-
## NOTE: You will need a provider that provides embeddings. So even if you use Claude, you will
|
|
1554
|
+
## NOTE: You will need a provider that provides embeddings. So even if you use Claude, you will
|
|
1687
1555
|
## need to get embeddings using another provider, for example openai or our local-ai plugin
|
|
1688
1556
|
|
|
1689
1557
|
# OpenAI Configuration
|
|
@@ -1730,7 +1598,7 @@ ANTHROPIC_API_KEY=
|
|
|
1730
1598
|
|
|
1731
1599
|
|
|
1732
1600
|
# Highly recommended to use nomic-embed-text for embeddings
|
|
1733
|
-
# OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
|
1601
|
+
# OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
|
1734
1602
|
|
|
1735
1603
|
### DATABASE ###
|
|
1736
1604
|
# By default, Eliza will use a local pglite instance
|
|
@@ -1792,36 +1660,24 @@ async function getElizaDirectories(targetProjectDir) {
|
|
|
1792
1660
|
return { elizaDir, elizaDbDir, envFilePath };
|
|
1793
1661
|
}
|
|
1794
1662
|
async function ensureDir(dirPath) {
|
|
1795
|
-
if (!
|
|
1663
|
+
if (!existsSync8(dirPath)) {
|
|
1796
1664
|
await fs7.mkdir(dirPath, { recursive: true });
|
|
1797
1665
|
logger9.debug(`Created directory: ${dirPath}`);
|
|
1798
1666
|
}
|
|
1799
1667
|
}
|
|
1800
1668
|
async function setupEnvFile(envFilePath) {
|
|
1801
1669
|
try {
|
|
1802
|
-
const envExists =
|
|
1670
|
+
const envExists = existsSync8(envFilePath);
|
|
1803
1671
|
if (!envExists) {
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
await fs7.writeFile(envFilePath, formattedContent, "utf8");
|
|
1807
|
-
const processEnvCount = Object.keys(process.env).filter(
|
|
1808
|
-
(key) => process.env[key] && process.env[key].trim() !== ""
|
|
1809
|
-
).length;
|
|
1810
|
-
logger9.info(
|
|
1811
|
-
`[Config] Created .env file with ${processEnvCount} variables from process.env merged with example variables at: ${envFilePath}`
|
|
1812
|
-
);
|
|
1672
|
+
await fs7.writeFile(envFilePath, SAMPLE_ENV_TEMPLATE, "utf8");
|
|
1673
|
+
logger9.info(`[Config] Created .env file with template variables at: ${envFilePath}`);
|
|
1813
1674
|
} else {
|
|
1814
1675
|
const content = await fs7.readFile(envFilePath, "utf8");
|
|
1815
1676
|
const trimmedContent = content.trim();
|
|
1816
1677
|
if (trimmedContent === "") {
|
|
1817
|
-
|
|
1818
|
-
const formattedContent = formatEnvFileWithTemplate(mergedVars, SAMPLE_ENV_TEMPLATE);
|
|
1819
|
-
await fs7.writeFile(envFilePath, formattedContent, "utf8");
|
|
1820
|
-
const processEnvCount = Object.keys(process.env).filter(
|
|
1821
|
-
(key) => process.env[key] && process.env[key].trim() !== ""
|
|
1822
|
-
).length;
|
|
1678
|
+
await fs7.writeFile(envFilePath, SAMPLE_ENV_TEMPLATE, "utf8");
|
|
1823
1679
|
logger9.info(
|
|
1824
|
-
`[Config] Populated empty .env file with
|
|
1680
|
+
`[Config] Populated empty .env file with template variables at: ${envFilePath}`
|
|
1825
1681
|
);
|
|
1826
1682
|
} else {
|
|
1827
1683
|
logger9.debug(`[Config] .env file already exists and has content at: ${envFilePath}`);
|
|
@@ -1840,11 +1696,11 @@ async function ensureElizaDir(targetProjectDir) {
|
|
|
1840
1696
|
await ensureDir(dirs.elizaDir);
|
|
1841
1697
|
const registryCachePath = path9.join(dirs.elizaDir, "registry-cache.json");
|
|
1842
1698
|
const configPath = path9.join(dirs.elizaDir, "config.json");
|
|
1843
|
-
if (!
|
|
1699
|
+
if (!existsSync8(registryCachePath)) {
|
|
1844
1700
|
await fs7.writeFile(registryCachePath, JSON.stringify({}, null, 2), "utf8");
|
|
1845
1701
|
logger9.debug(`Created registry cache file: ${registryCachePath}`);
|
|
1846
1702
|
}
|
|
1847
|
-
if (!
|
|
1703
|
+
if (!existsSync8(configPath)) {
|
|
1848
1704
|
await fs7.writeFile(configPath, JSON.stringify({ version: "1.0.0" }, null, 2), "utf8");
|
|
1849
1705
|
logger9.debug(`Created config file: ${configPath}`);
|
|
1850
1706
|
}
|
|
@@ -1874,7 +1730,7 @@ async function storePostgresUrl(url, envFilePath) {
|
|
|
1874
1730
|
if (!url) return;
|
|
1875
1731
|
try {
|
|
1876
1732
|
let content = "";
|
|
1877
|
-
if (
|
|
1733
|
+
if (existsSync8(envFilePath)) {
|
|
1878
1734
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
1879
1735
|
}
|
|
1880
1736
|
const lines = content.split("\n").filter((line) => !line.startsWith("POSTGRES_URL="));
|
|
@@ -1891,7 +1747,7 @@ async function storePgliteDataDir(dataDir, envFilePath) {
|
|
|
1891
1747
|
if (!dataDir) return;
|
|
1892
1748
|
try {
|
|
1893
1749
|
let content = "";
|
|
1894
|
-
if (
|
|
1750
|
+
if (existsSync8(envFilePath)) {
|
|
1895
1751
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
1896
1752
|
}
|
|
1897
1753
|
const lines = content.split("\n").filter((line) => !line.startsWith("PGLITE_DATA_DIR="));
|
|
@@ -1905,8 +1761,8 @@ async function storePgliteDataDir(dataDir, envFilePath) {
|
|
|
1905
1761
|
}
|
|
1906
1762
|
}
|
|
1907
1763
|
async function promptAndStorePostgresUrl(envFilePath) {
|
|
1908
|
-
|
|
1909
|
-
const response = await
|
|
1764
|
+
clack2.intro("\u{1F5C4}\uFE0F PostgreSQL Configuration");
|
|
1765
|
+
const response = await clack2.text({
|
|
1910
1766
|
message: "Enter your Postgres URL:",
|
|
1911
1767
|
placeholder: "postgresql://user:password@host:port/dbname",
|
|
1912
1768
|
validate: (value) => {
|
|
@@ -1918,20 +1774,20 @@ async function promptAndStorePostgresUrl(envFilePath) {
|
|
|
1918
1774
|
return void 0;
|
|
1919
1775
|
}
|
|
1920
1776
|
});
|
|
1921
|
-
if (
|
|
1922
|
-
|
|
1777
|
+
if (clack2.isCancel(response)) {
|
|
1778
|
+
clack2.cancel("Operation cancelled.");
|
|
1923
1779
|
return null;
|
|
1924
1780
|
}
|
|
1925
|
-
const spinner2 =
|
|
1781
|
+
const spinner2 = clack2.spinner();
|
|
1926
1782
|
spinner2.start("Saving PostgreSQL configuration...");
|
|
1927
1783
|
try {
|
|
1928
1784
|
await storePostgresUrl(response, envFilePath);
|
|
1929
1785
|
spinner2.stop("PostgreSQL configuration saved successfully!");
|
|
1930
|
-
|
|
1786
|
+
clack2.outro("\u2713 Database connection configured");
|
|
1931
1787
|
return response;
|
|
1932
1788
|
} catch (error) {
|
|
1933
1789
|
spinner2.stop("Failed to save configuration");
|
|
1934
|
-
|
|
1790
|
+
clack2.log.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1935
1791
|
return null;
|
|
1936
1792
|
}
|
|
1937
1793
|
}
|
|
@@ -1951,7 +1807,7 @@ async function storeOpenAIKey(key, envFilePath) {
|
|
|
1951
1807
|
if (!key) return;
|
|
1952
1808
|
try {
|
|
1953
1809
|
let content = "";
|
|
1954
|
-
if (
|
|
1810
|
+
if (existsSync8(envFilePath)) {
|
|
1955
1811
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
1956
1812
|
}
|
|
1957
1813
|
const lines = content.split("\n").filter((line) => !line.startsWith("OPENAI_API_KEY="));
|
|
@@ -1968,7 +1824,7 @@ async function storeGoogleKey(key, envFilePath) {
|
|
|
1968
1824
|
if (!key) return;
|
|
1969
1825
|
try {
|
|
1970
1826
|
let content = "";
|
|
1971
|
-
if (
|
|
1827
|
+
if (existsSync8(envFilePath)) {
|
|
1972
1828
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
1973
1829
|
}
|
|
1974
1830
|
const lines = content.split("\n").filter((line) => !line.startsWith("GOOGLE_GENERATIVE_AI_API_KEY="));
|
|
@@ -1985,7 +1841,7 @@ async function storeAnthropicKey(key, envFilePath) {
|
|
|
1985
1841
|
if (!key) return;
|
|
1986
1842
|
try {
|
|
1987
1843
|
let content = "";
|
|
1988
|
-
if (
|
|
1844
|
+
if (existsSync8(envFilePath)) {
|
|
1989
1845
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
1990
1846
|
}
|
|
1991
1847
|
const lines = content.split("\n").filter((line) => !line.startsWith("ANTHROPIC_API_KEY="));
|
|
@@ -1999,13 +1855,13 @@ async function storeAnthropicKey(key, envFilePath) {
|
|
|
1999
1855
|
}
|
|
2000
1856
|
}
|
|
2001
1857
|
async function promptAndStoreProviderConfig(config, envFilePath) {
|
|
2002
|
-
|
|
1858
|
+
clack2.intro(`${config.icon} ${config.name} Configuration`);
|
|
2003
1859
|
if (config.noteText) {
|
|
2004
|
-
|
|
1860
|
+
clack2.note(config.noteText, "API Key Information");
|
|
2005
1861
|
}
|
|
2006
1862
|
const results = {};
|
|
2007
1863
|
for (const input of config.inputs) {
|
|
2008
|
-
const promptFn = input.type === "password" ?
|
|
1864
|
+
const promptFn = input.type === "password" ? clack2.password : clack2.text;
|
|
2009
1865
|
const promptConfig = {
|
|
2010
1866
|
message: input.message,
|
|
2011
1867
|
validate: input.validate
|
|
@@ -2013,22 +1869,22 @@ async function promptAndStoreProviderConfig(config, envFilePath) {
|
|
|
2013
1869
|
if (input.placeholder) promptConfig.placeholder = input.placeholder;
|
|
2014
1870
|
if (input.initialValue) promptConfig.initialValue = input.initialValue;
|
|
2015
1871
|
const response = await promptFn(promptConfig);
|
|
2016
|
-
if (
|
|
2017
|
-
|
|
1872
|
+
if (clack2.isCancel(response)) {
|
|
1873
|
+
clack2.cancel("Operation cancelled.");
|
|
2018
1874
|
return null;
|
|
2019
1875
|
}
|
|
2020
1876
|
results[input.key] = input.type === "text" ? response.trim() : response;
|
|
2021
1877
|
}
|
|
2022
|
-
const spinner2 =
|
|
1878
|
+
const spinner2 = clack2.spinner();
|
|
2023
1879
|
spinner2.start(`Saving ${config.name} configuration...`);
|
|
2024
1880
|
try {
|
|
2025
1881
|
await config.storeFunction(results, envFilePath);
|
|
2026
1882
|
spinner2.stop(`${config.name} configuration saved successfully!`);
|
|
2027
|
-
|
|
1883
|
+
clack2.outro(`\u2713 ${config.successMessage}`);
|
|
2028
1884
|
return results;
|
|
2029
1885
|
} catch (error) {
|
|
2030
1886
|
spinner2.stop("Failed to save configuration");
|
|
2031
|
-
|
|
1887
|
+
clack2.log.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
2032
1888
|
return null;
|
|
2033
1889
|
}
|
|
2034
1890
|
}
|
|
@@ -2051,8 +1907,8 @@ async function promptAndStoreOpenAIKey(envFilePath) {
|
|
|
2051
1907
|
storeFunction: async (results, envPath) => {
|
|
2052
1908
|
const isValid = isValidOpenAIKey(results.key);
|
|
2053
1909
|
if (!isValid) {
|
|
2054
|
-
|
|
2055
|
-
|
|
1910
|
+
clack2.log.warn("Invalid API key format detected. Expected format: sk-...");
|
|
1911
|
+
clack2.log.warn("The key has been saved but may not work correctly.");
|
|
2056
1912
|
}
|
|
2057
1913
|
await storeOpenAIKey(results.key, envPath);
|
|
2058
1914
|
},
|
|
@@ -2080,8 +1936,8 @@ async function promptAndStoreAnthropicKey(envFilePath) {
|
|
|
2080
1936
|
storeFunction: async (results, envPath) => {
|
|
2081
1937
|
const isValid = isValidAnthropicKey(results.key);
|
|
2082
1938
|
if (!isValid) {
|
|
2083
|
-
|
|
2084
|
-
|
|
1939
|
+
clack2.log.warn("Invalid API key format detected. Expected format: sk-ant-...");
|
|
1940
|
+
clack2.log.warn("The key has been saved but may not work correctly.");
|
|
2085
1941
|
}
|
|
2086
1942
|
await storeAnthropicKey(results.key, envPath);
|
|
2087
1943
|
},
|
|
@@ -2103,7 +1959,7 @@ async function storeOllamaConfig(config, envFilePath) {
|
|
|
2103
1959
|
if (!config.endpoint || !config.model) return;
|
|
2104
1960
|
try {
|
|
2105
1961
|
let content = "";
|
|
2106
|
-
if (
|
|
1962
|
+
if (existsSync8(envFilePath)) {
|
|
2107
1963
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
2108
1964
|
}
|
|
2109
1965
|
const lines = content.split("\n").filter(
|
|
@@ -2157,7 +2013,7 @@ async function promptAndStoreOllamaEmbeddingConfig(envFilePath) {
|
|
|
2157
2013
|
storeFunction: async (results, envPath) => {
|
|
2158
2014
|
try {
|
|
2159
2015
|
let content = "";
|
|
2160
|
-
if (
|
|
2016
|
+
if (existsSync8(envPath)) {
|
|
2161
2017
|
content = await fs7.readFile(envPath, "utf8");
|
|
2162
2018
|
}
|
|
2163
2019
|
const lines = content.split("\n").filter(
|
|
@@ -2258,10 +2114,10 @@ async function promptAndStoreGoogleKey(envFilePath) {
|
|
|
2258
2114
|
storeFunction: async (results, envPath) => {
|
|
2259
2115
|
const isValid = isValidGoogleKey(results.key);
|
|
2260
2116
|
if (!isValid) {
|
|
2261
|
-
|
|
2117
|
+
clack2.log.warn(
|
|
2262
2118
|
"Invalid API key format detected. Expected format: 39 character alphanumeric key"
|
|
2263
2119
|
);
|
|
2264
|
-
|
|
2120
|
+
clack2.log.warn("The key has been saved but may not work correctly.");
|
|
2265
2121
|
}
|
|
2266
2122
|
await storeGoogleKey(results.key, envPath);
|
|
2267
2123
|
},
|
|
@@ -2278,7 +2134,7 @@ async function storeOpenRouterKey(key, envFilePath) {
|
|
|
2278
2134
|
if (!key) return;
|
|
2279
2135
|
try {
|
|
2280
2136
|
let content = "";
|
|
2281
|
-
if (
|
|
2137
|
+
if (existsSync8(envFilePath)) {
|
|
2282
2138
|
content = await fs7.readFile(envFilePath, "utf8");
|
|
2283
2139
|
}
|
|
2284
2140
|
const lines = content.split("\n").filter((line) => !line.startsWith("OPENROUTER_API_KEY="));
|
|
@@ -2310,8 +2166,8 @@ async function promptAndStoreOpenRouterKey(envFilePath) {
|
|
|
2310
2166
|
storeFunction: async (results, envPath) => {
|
|
2311
2167
|
const isValid = isValidOpenRouterKey(results.key);
|
|
2312
2168
|
if (!isValid) {
|
|
2313
|
-
|
|
2314
|
-
|
|
2169
|
+
clack2.log.warn("Invalid API key format detected. Expected format: sk-or-...");
|
|
2170
|
+
clack2.log.warn("The key has been saved but may not work correctly.");
|
|
2315
2171
|
}
|
|
2316
2172
|
await storeOpenRouterKey(results.key, envPath);
|
|
2317
2173
|
},
|
|
@@ -2373,73 +2229,10 @@ async function resolveConfigPaths(cwd, config) {
|
|
|
2373
2229
|
}
|
|
2374
2230
|
async function loadEnvironment(projectDir = process.cwd()) {
|
|
2375
2231
|
const envPath = resolveEnvFile(projectDir);
|
|
2376
|
-
if (
|
|
2232
|
+
if (existsSync8(envPath)) {
|
|
2377
2233
|
dotenv2.config({ path: envPath });
|
|
2378
2234
|
}
|
|
2379
2235
|
}
|
|
2380
|
-
function mergeProcessEnvWithTemplate(templateContent) {
|
|
2381
|
-
const result = {};
|
|
2382
|
-
const processedKeys = /* @__PURE__ */ new Set();
|
|
2383
|
-
const templateLines = templateContent.split("\n");
|
|
2384
|
-
const templateVars = {};
|
|
2385
|
-
for (const line of templateLines) {
|
|
2386
|
-
const trimmedLine = line.trim();
|
|
2387
|
-
if (trimmedLine && !trimmedLine.startsWith("#") && trimmedLine.includes("=")) {
|
|
2388
|
-
const equalIndex = trimmedLine.indexOf("=");
|
|
2389
|
-
const key = trimmedLine.substring(0, equalIndex).trim();
|
|
2390
|
-
const value = trimmedLine.substring(equalIndex + 1).trim();
|
|
2391
|
-
if (key) {
|
|
2392
|
-
templateVars[key] = value;
|
|
2393
|
-
}
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
2397
|
-
if (value && value.trim() !== "") {
|
|
2398
|
-
result[key] = value;
|
|
2399
|
-
processedKeys.add(key);
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
for (const [key, value] of Object.entries(templateVars)) {
|
|
2403
|
-
if (!processedKeys.has(key)) {
|
|
2404
|
-
result[key] = value;
|
|
2405
|
-
processedKeys.add(key);
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
return result;
|
|
2409
|
-
}
|
|
2410
|
-
function formatEnvFileWithTemplate(envVars, templateContent) {
|
|
2411
|
-
const lines = [];
|
|
2412
|
-
const processedKeys = /* @__PURE__ */ new Set();
|
|
2413
|
-
const templateLines = templateContent.split("\n");
|
|
2414
|
-
for (const line of templateLines) {
|
|
2415
|
-
const trimmedLine = line.trim();
|
|
2416
|
-
if (!trimmedLine || trimmedLine.startsWith("#") || !trimmedLine.includes("=")) {
|
|
2417
|
-
lines.push(line);
|
|
2418
|
-
} else {
|
|
2419
|
-
const equalIndex = trimmedLine.indexOf("=");
|
|
2420
|
-
const key = trimmedLine.substring(0, equalIndex).trim();
|
|
2421
|
-
if (key && envVars.hasOwnProperty(key)) {
|
|
2422
|
-
lines.push(`${key}=${envVars[key]}`);
|
|
2423
|
-
processedKeys.add(key);
|
|
2424
|
-
} else {
|
|
2425
|
-
lines.push(line);
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
const newVars = [];
|
|
2430
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
2431
|
-
if (!processedKeys.has(key)) {
|
|
2432
|
-
newVars.push(`${key}=${value}`);
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
if (newVars.length > 0) {
|
|
2436
|
-
lines.push("");
|
|
2437
|
-
lines.push("### Additional Environment Variables from Runtime ###");
|
|
2438
|
-
lines.push("# Variables found in process.env that were not in the template");
|
|
2439
|
-
lines.push(...newVars);
|
|
2440
|
-
}
|
|
2441
|
-
return lines.join("\n");
|
|
2442
|
-
}
|
|
2443
2236
|
|
|
2444
2237
|
// src/utils/get-package-info.ts
|
|
2445
2238
|
async function getPackageVersion(packageName) {
|
|
@@ -2479,9 +2272,9 @@ async function getPackageInfo() {
|
|
|
2479
2272
|
import { promises as fs8 } from "fs";
|
|
2480
2273
|
import path10 from "path";
|
|
2481
2274
|
import { logger as logger10 } from "@elizaos/core";
|
|
2482
|
-
import { existsSync as
|
|
2275
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2483
2276
|
import { execa as execa5 } from "execa";
|
|
2484
|
-
import * as
|
|
2277
|
+
import * as clack3 from "@clack/prompts";
|
|
2485
2278
|
var GITHUB_API_URL = "https://api.github.com";
|
|
2486
2279
|
async function validateGitHubToken(token) {
|
|
2487
2280
|
try {
|
|
@@ -2711,10 +2504,10 @@ async function createBranch(token, owner, repo, branch, baseBranch = "main") {
|
|
|
2711
2504
|
return false;
|
|
2712
2505
|
}
|
|
2713
2506
|
}
|
|
2714
|
-
async function getFileContent(token, owner, repo,
|
|
2507
|
+
async function getFileContent(token, owner, repo, path20, branch = "main") {
|
|
2715
2508
|
try {
|
|
2716
2509
|
const response = await fetch(
|
|
2717
|
-
`${GITHUB_API_URL}/repos/${owner}/${repo}/contents/${
|
|
2510
|
+
`${GITHUB_API_URL}/repos/${owner}/${repo}/contents/${path20}?ref=${branch}`,
|
|
2718
2511
|
{
|
|
2719
2512
|
headers: {
|
|
2720
2513
|
Authorization: `token ${token}`,
|
|
@@ -2731,14 +2524,14 @@ async function getFileContent(token, owner, repo, path19, branch = "main") {
|
|
|
2731
2524
|
return null;
|
|
2732
2525
|
}
|
|
2733
2526
|
}
|
|
2734
|
-
async function updateFile(token, owner, repo,
|
|
2527
|
+
async function updateFile(token, owner, repo, path20, content, message, branch = "main") {
|
|
2735
2528
|
try {
|
|
2736
|
-
const existingContent = await getFileContent(token, owner, repo,
|
|
2529
|
+
const existingContent = await getFileContent(token, owner, repo, path20, branch);
|
|
2737
2530
|
const method = "PUT";
|
|
2738
2531
|
let sha;
|
|
2739
2532
|
if (existingContent !== null) {
|
|
2740
2533
|
const response2 = await fetch(
|
|
2741
|
-
`${GITHUB_API_URL}/repos/${owner}/${repo}/contents/${
|
|
2534
|
+
`${GITHUB_API_URL}/repos/${owner}/${repo}/contents/${path20}?ref=${branch}`,
|
|
2742
2535
|
{
|
|
2743
2536
|
headers: {
|
|
2744
2537
|
Authorization: `token ${token}`,
|
|
@@ -2751,7 +2544,7 @@ async function updateFile(token, owner, repo, path19, content, message, branch =
|
|
|
2751
2544
|
sha = data.sha;
|
|
2752
2545
|
}
|
|
2753
2546
|
}
|
|
2754
|
-
const fileUrl = `${GITHUB_API_URL}/repos/${owner}/${repo}/contents/${
|
|
2547
|
+
const fileUrl = `${GITHUB_API_URL}/repos/${owner}/${repo}/contents/${path20}`;
|
|
2755
2548
|
logger10.info(`Updating file at: ${fileUrl}`);
|
|
2756
2549
|
const requestBody = {
|
|
2757
2550
|
message,
|
|
@@ -2777,7 +2570,7 @@ async function updateFile(token, owner, repo, path19, content, message, branch =
|
|
|
2777
2570
|
logger10.error(`Failed to update file: ${response.status} ${response.statusText}`);
|
|
2778
2571
|
logger10.error(`Response body: ${errorBody}`);
|
|
2779
2572
|
if (response.status === 404) {
|
|
2780
|
-
logger10.error(`Repository or path not found: ${owner}/${repo}/${
|
|
2573
|
+
logger10.error(`Repository or path not found: ${owner}/${repo}/${path20}`);
|
|
2781
2574
|
const repoCheck = await fetch(`${GITHUB_API_URL}/repos/${owner}/${repo}`, {
|
|
2782
2575
|
headers: {
|
|
2783
2576
|
Authorization: `token ${token}`,
|
|
@@ -2856,7 +2649,7 @@ async function getGitHubCredentials() {
|
|
|
2856
2649
|
}
|
|
2857
2650
|
logger10.warn("Invalid GitHub token found in environment variables");
|
|
2858
2651
|
}
|
|
2859
|
-
const { getGitHubToken: getGitHubToken2 } = await import("./registry-
|
|
2652
|
+
const { getGitHubToken: getGitHubToken2 } = await import("./registry-FBPEGL2T.js");
|
|
2860
2653
|
const token = await getGitHubToken2() || void 0;
|
|
2861
2654
|
if (token) {
|
|
2862
2655
|
const isValid2 = await validateGitHubToken(token);
|
|
@@ -2871,8 +2664,8 @@ async function getGitHubCredentials() {
|
|
|
2871
2664
|
logger10.warn("Stored GitHub token is invalid, will prompt for new credentials");
|
|
2872
2665
|
}
|
|
2873
2666
|
}
|
|
2874
|
-
|
|
2875
|
-
|
|
2667
|
+
clack3.intro("\u{1F510} GitHub Authentication Required");
|
|
2668
|
+
clack3.note(
|
|
2876
2669
|
`To create a GitHub Personal Access Token (Classic):
|
|
2877
2670
|
1. Go to https://github.com/settings/tokens/new
|
|
2878
2671
|
2. Give your token a descriptive name (e.g., "ElizaOS CLI")
|
|
@@ -2887,20 +2680,20 @@ async function getGitHubCredentials() {
|
|
|
2887
2680
|
NOTE: You must use a Classic token, not a Fine-grained token`,
|
|
2888
2681
|
"Setup Instructions"
|
|
2889
2682
|
);
|
|
2890
|
-
const promptedUsername = await
|
|
2683
|
+
const promptedUsername = await clack3.text({
|
|
2891
2684
|
message: "Enter your GitHub username:",
|
|
2892
2685
|
validate: (value) => value ? void 0 : "Username is required"
|
|
2893
2686
|
});
|
|
2894
|
-
if (
|
|
2895
|
-
|
|
2687
|
+
if (clack3.isCancel(promptedUsername)) {
|
|
2688
|
+
clack3.cancel("Operation cancelled.");
|
|
2896
2689
|
return null;
|
|
2897
2690
|
}
|
|
2898
|
-
const promptedToken = await
|
|
2691
|
+
const promptedToken = await clack3.password({
|
|
2899
2692
|
message: "Enter your GitHub Personal Access Token (with repo, read:org, and workflow scopes):",
|
|
2900
2693
|
validate: (value) => value ? void 0 : "Token is required"
|
|
2901
2694
|
});
|
|
2902
|
-
if (
|
|
2903
|
-
|
|
2695
|
+
if (clack3.isCancel(promptedToken)) {
|
|
2696
|
+
clack3.cancel("Operation cancelled.");
|
|
2904
2697
|
return null;
|
|
2905
2698
|
}
|
|
2906
2699
|
const isValid = await validateGitHubToken(promptedToken);
|
|
@@ -2916,10 +2709,10 @@ async function saveGitHubCredentials(username, token) {
|
|
|
2916
2709
|
const envInfo = await UserEnvironment.getInstanceInfo();
|
|
2917
2710
|
const { elizaDir, envFilePath } = envInfo.paths;
|
|
2918
2711
|
logger10.debug("[GitHub] Saving credentials");
|
|
2919
|
-
if (!
|
|
2712
|
+
if (!existsSync9(elizaDir)) {
|
|
2920
2713
|
await fs8.mkdir(elizaDir, { recursive: true });
|
|
2921
2714
|
}
|
|
2922
|
-
if (!
|
|
2715
|
+
if (!existsSync9(envFilePath)) {
|
|
2923
2716
|
await fs8.writeFile(envFilePath, "", { encoding: "utf8" });
|
|
2924
2717
|
}
|
|
2925
2718
|
const currentContent = await fs8.readFile(envFilePath, "utf8");
|
|
@@ -2943,11 +2736,11 @@ async function saveGitHubCredentials(username, token) {
|
|
|
2943
2736
|
process.env.GITHUB_TOKEN = token;
|
|
2944
2737
|
logger10.success("GitHub credentials saved");
|
|
2945
2738
|
}
|
|
2946
|
-
async function ensureDirectory(token, repo,
|
|
2739
|
+
async function ensureDirectory(token, repo, path20, branch) {
|
|
2947
2740
|
try {
|
|
2948
2741
|
try {
|
|
2949
2742
|
const response = await fetch(
|
|
2950
|
-
`${GITHUB_API_URL}/repos/${repo}/contents/${
|
|
2743
|
+
`${GITHUB_API_URL}/repos/${repo}/contents/${path20}?ref=${branch}`,
|
|
2951
2744
|
{
|
|
2952
2745
|
headers: {
|
|
2953
2746
|
Authorization: `token ${token}`,
|
|
@@ -2956,27 +2749,27 @@ async function ensureDirectory(token, repo, path19, branch) {
|
|
|
2956
2749
|
}
|
|
2957
2750
|
);
|
|
2958
2751
|
if (response.status === 200) {
|
|
2959
|
-
logger10.info(`Directory ${
|
|
2752
|
+
logger10.info(`Directory ${path20} already exists`);
|
|
2960
2753
|
return true;
|
|
2961
2754
|
}
|
|
2962
2755
|
} catch (error) {
|
|
2963
|
-
logger10.info(`Directory ${
|
|
2756
|
+
logger10.info(`Directory ${path20} doesn't exist, creating it`);
|
|
2964
2757
|
}
|
|
2965
|
-
const placeholderPath = `${
|
|
2758
|
+
const placeholderPath = `${path20}/.gitkeep`;
|
|
2966
2759
|
const result = await updateFile(
|
|
2967
2760
|
token,
|
|
2968
2761
|
repo,
|
|
2969
2762
|
placeholderPath,
|
|
2970
2763
|
"",
|
|
2971
2764
|
// Empty content for placeholder
|
|
2972
|
-
`Create directory: ${
|
|
2765
|
+
`Create directory: ${path20}`,
|
|
2973
2766
|
branch
|
|
2974
2767
|
);
|
|
2975
2768
|
if (result) {
|
|
2976
|
-
logger10.success(`Created directory: ${
|
|
2769
|
+
logger10.success(`Created directory: ${path20}`);
|
|
2977
2770
|
return true;
|
|
2978
2771
|
}
|
|
2979
|
-
logger10.error(`Failed to create directory: ${
|
|
2772
|
+
logger10.error(`Failed to create directory: ${path20}`);
|
|
2980
2773
|
return false;
|
|
2981
2774
|
} catch (error) {
|
|
2982
2775
|
logger10.error(
|
|
@@ -3071,7 +2864,7 @@ async function createGitHubRepository(token, repoName, description, isPrivate =
|
|
|
3071
2864
|
}
|
|
3072
2865
|
async function pushToGitHub(cwd, repoUrl, branch = "main") {
|
|
3073
2866
|
try {
|
|
3074
|
-
const gitDirExists =
|
|
2867
|
+
const gitDirExists = existsSync9(path10.join(cwd, ".git"));
|
|
3075
2868
|
let hasCorrectRemote = false;
|
|
3076
2869
|
if (gitDirExists) {
|
|
3077
2870
|
try {
|
|
@@ -3367,7 +3160,7 @@ async function setAgentConfig(opts) {
|
|
|
3367
3160
|
|
|
3368
3161
|
// src/commands/agent/actions/lifecycle.ts
|
|
3369
3162
|
import { logger as logger12 } from "@elizaos/core";
|
|
3370
|
-
import { existsSync as
|
|
3163
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
|
|
3371
3164
|
import path12 from "path";
|
|
3372
3165
|
async function startAgent(options) {
|
|
3373
3166
|
try {
|
|
@@ -3414,7 +3207,7 @@ async function startAgent(options) {
|
|
|
3414
3207
|
if (options.path) {
|
|
3415
3208
|
try {
|
|
3416
3209
|
const filePath = path12.resolve(process.cwd(), options.path);
|
|
3417
|
-
if (!
|
|
3210
|
+
if (!existsSync10(filePath)) {
|
|
3418
3211
|
throw new Error(`File not found at path: ${filePath}`);
|
|
3419
3212
|
}
|
|
3420
3213
|
const fileContent = readFileSync6(filePath, "utf8");
|
|
@@ -3622,18 +3415,18 @@ agent.command("set").description("Update agent configuration").requiredOption("-
|
|
|
3622
3415
|
agent.command("clear-memories").alias("clear").description("Clear all memories for an agent").requiredOption("-n, --name <name>", "agent id, name, or index number from list").option("-r, --remote-url <url>", "URL of the remote agent runtime").option("-p, --port <port>", "Port to listen on", (val) => Number.parseInt(val)).action(clearAgentMemories);
|
|
3623
3416
|
|
|
3624
3417
|
// src/utils/handle-error.ts
|
|
3625
|
-
import
|
|
3418
|
+
import colors from "yoctocolors";
|
|
3626
3419
|
function handleError(error) {
|
|
3627
3420
|
const isNoSpace = error instanceof Error && (error.message.includes("no space left on device") || error.message.includes("ENOSPC")) || typeof error === "string" && (error.includes("no space left on device") || error.includes("ENOSPC"));
|
|
3628
3421
|
if (isNoSpace) {
|
|
3629
3422
|
logger13.error(
|
|
3630
|
-
|
|
3423
|
+
colors.red("ERROR: No space left on device! Please free up disk space and try again.")
|
|
3631
3424
|
);
|
|
3632
3425
|
if (error instanceof Error) {
|
|
3633
|
-
logger13.error(
|
|
3634
|
-
logger13.error(
|
|
3426
|
+
logger13.error(colors.red(error.message));
|
|
3427
|
+
logger13.error(colors.red(error.stack || ""));
|
|
3635
3428
|
} else {
|
|
3636
|
-
logger13.error(
|
|
3429
|
+
logger13.error(colors.red(String(error)));
|
|
3637
3430
|
}
|
|
3638
3431
|
} else {
|
|
3639
3432
|
logger13.error("An error occurred:", error);
|
|
@@ -3661,7 +3454,17 @@ async function checkServer(opts) {
|
|
|
3661
3454
|
}
|
|
3662
3455
|
|
|
3663
3456
|
// src/utils/helpers.ts
|
|
3664
|
-
import
|
|
3457
|
+
import colors2 from "yoctocolors";
|
|
3458
|
+
import path13 from "path";
|
|
3459
|
+
function getDisplayDirectory(targetDir) {
|
|
3460
|
+
if (targetDir === ".") {
|
|
3461
|
+
return path13.basename(process.cwd());
|
|
3462
|
+
}
|
|
3463
|
+
if (targetDir.startsWith("/") || targetDir.match(/^[a-zA-Z]:[\\\/]/) || targetDir.startsWith("\\\\")) {
|
|
3464
|
+
return path13.basename(targetDir);
|
|
3465
|
+
}
|
|
3466
|
+
return targetDir;
|
|
3467
|
+
}
|
|
3665
3468
|
function displayAgent(data, title = "Agent Review") {
|
|
3666
3469
|
logHeader(title);
|
|
3667
3470
|
console.log(`Name: ${data.name}`);
|
|
@@ -3678,7 +3481,7 @@ function displayAgent(data, title = "Agent Review") {
|
|
|
3678
3481
|
displaySection("Post Examples", data.postExamples);
|
|
3679
3482
|
if (data.messageExamples && data.messageExamples.length > 0) {
|
|
3680
3483
|
console.log(`
|
|
3681
|
-
${
|
|
3484
|
+
${colors2.cyan("Message Examples:")}`);
|
|
3682
3485
|
console.log(
|
|
3683
3486
|
data.messageExamples.map((conversation, i) => {
|
|
3684
3487
|
const messages = formatConversation(conversation);
|
|
@@ -3698,7 +3501,7 @@ function formatConversation(conversation) {
|
|
|
3698
3501
|
function displaySection(title, items) {
|
|
3699
3502
|
if (!items || items.length === 0) return;
|
|
3700
3503
|
console.log(`
|
|
3701
|
-
${
|
|
3504
|
+
${colors2.cyan(`${title}:`)}`);
|
|
3702
3505
|
for (const item of items) {
|
|
3703
3506
|
console.log(` ${item}`);
|
|
3704
3507
|
}
|
|
@@ -3708,10 +3511,10 @@ function logHeader(title) {
|
|
|
3708
3511
|
const titleStr = `=== ${title} ===`;
|
|
3709
3512
|
const paddedTitle = " ".repeat(padding) + titleStr + " ".repeat(padding);
|
|
3710
3513
|
const borderLength = paddedTitle.length;
|
|
3711
|
-
const topBorder =
|
|
3712
|
-
const bottomBorder =
|
|
3713
|
-
const coloredTitle = `${" ".repeat(padding)}=== ${
|
|
3714
|
-
const middleRow =
|
|
3514
|
+
const topBorder = colors2.green(`\u250C${"\u2500".repeat(borderLength)}\u2510`);
|
|
3515
|
+
const bottomBorder = colors2.green(`\u2514${"\u2500".repeat(borderLength)}\u2518`);
|
|
3516
|
+
const coloredTitle = `${" ".repeat(padding)}=== ${colors2.green(title)} ===${" ".repeat(padding)}`;
|
|
3517
|
+
const middleRow = colors2.green("\u2502") + coloredTitle + colors2.green("\u2502");
|
|
3715
3518
|
console.log(`
|
|
3716
3519
|
${topBorder}
|
|
3717
3520
|
${middleRow}
|
|
@@ -3720,18 +3523,18 @@ ${bottomBorder}`);
|
|
|
3720
3523
|
|
|
3721
3524
|
// src/utils/install-plugin.ts
|
|
3722
3525
|
import { logger as logger18 } from "@elizaos/core";
|
|
3723
|
-
import { existsSync as
|
|
3724
|
-
import
|
|
3526
|
+
import { existsSync as existsSync14 } from "fs";
|
|
3527
|
+
import path17 from "path";
|
|
3725
3528
|
|
|
3726
3529
|
// src/utils/load-plugin.ts
|
|
3727
3530
|
import { logger as logger15 } from "@elizaos/core";
|
|
3728
|
-
import { existsSync as
|
|
3729
|
-
import
|
|
3531
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
|
|
3532
|
+
import path15 from "path";
|
|
3730
3533
|
|
|
3731
3534
|
// src/utils/plugin-context.ts
|
|
3732
3535
|
import { logger as logger14 } from "@elizaos/core";
|
|
3733
|
-
import { existsSync as
|
|
3734
|
-
import
|
|
3536
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
3537
|
+
import path14 from "path";
|
|
3735
3538
|
function normalizeForComparison(name) {
|
|
3736
3539
|
const normalized = normalizePluginName(name)[0] || name;
|
|
3737
3540
|
return normalized.toLowerCase();
|
|
@@ -3742,7 +3545,7 @@ function detectPluginContext(pluginName) {
|
|
|
3742
3545
|
if (directoryInfo.type !== "elizaos-plugin" || !directoryInfo.hasPackageJson) {
|
|
3743
3546
|
return { isLocalDevelopment: false };
|
|
3744
3547
|
}
|
|
3745
|
-
const packageJsonPath =
|
|
3548
|
+
const packageJsonPath = path14.join(cwd, "package.json");
|
|
3746
3549
|
let packageInfo;
|
|
3747
3550
|
try {
|
|
3748
3551
|
packageInfo = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
|
|
@@ -3752,13 +3555,13 @@ function detectPluginContext(pluginName) {
|
|
|
3752
3555
|
}
|
|
3753
3556
|
const normalizedRequestedPlugin = normalizeForComparison(pluginName);
|
|
3754
3557
|
const normalizedCurrentPackage = normalizeForComparison(packageInfo.name);
|
|
3755
|
-
const dirName =
|
|
3558
|
+
const dirName = path14.basename(cwd);
|
|
3756
3559
|
const normalizedDirName = normalizeForComparison(dirName);
|
|
3757
3560
|
const isCurrentPlugin = normalizedRequestedPlugin === normalizedCurrentPackage || normalizedRequestedPlugin === normalizedDirName;
|
|
3758
3561
|
if (isCurrentPlugin) {
|
|
3759
3562
|
const mainEntry = packageInfo.main || "dist/index.js";
|
|
3760
|
-
const localPath =
|
|
3761
|
-
const needsBuild = !
|
|
3563
|
+
const localPath = path14.resolve(cwd, mainEntry);
|
|
3564
|
+
const needsBuild = !existsSync11(localPath);
|
|
3762
3565
|
logger14.debug(`Detected local plugin development: ${pluginName}`);
|
|
3763
3566
|
logger14.debug(`Expected output: ${localPath}`);
|
|
3764
3567
|
logger14.debug(`Needs build: ${needsBuild}`);
|
|
@@ -3780,7 +3583,7 @@ async function ensurePluginBuilt(context) {
|
|
|
3780
3583
|
logger14.info("Plugin not built, attempting to build...");
|
|
3781
3584
|
try {
|
|
3782
3585
|
await buildProject(process.cwd(), true);
|
|
3783
|
-
if (localPath &&
|
|
3586
|
+
if (localPath && existsSync11(localPath)) {
|
|
3784
3587
|
logger14.success("Plugin built successfully");
|
|
3785
3588
|
return true;
|
|
3786
3589
|
} else {
|
|
@@ -3817,20 +3620,20 @@ Local plugin development detected for: ${pluginName}`);
|
|
|
3817
3620
|
// src/utils/load-plugin.ts
|
|
3818
3621
|
var DEFAULT_ENTRY_POINT = "dist/index.js";
|
|
3819
3622
|
function getGlobalNodeModulesPath() {
|
|
3820
|
-
const nodeDir =
|
|
3623
|
+
const nodeDir = path15.dirname(process.execPath);
|
|
3821
3624
|
if (process.platform === "win32") {
|
|
3822
|
-
return
|
|
3625
|
+
return path15.join(nodeDir, "node_modules");
|
|
3823
3626
|
} else {
|
|
3824
|
-
return
|
|
3627
|
+
return path15.join(nodeDir, "..", "lib", "node_modules");
|
|
3825
3628
|
}
|
|
3826
3629
|
}
|
|
3827
3630
|
function resolveNodeModulesPath(repository, ...segments) {
|
|
3828
|
-
return
|
|
3631
|
+
return path15.resolve(process.cwd(), "node_modules", repository, ...segments);
|
|
3829
3632
|
}
|
|
3830
3633
|
async function readPackageJson(repository) {
|
|
3831
3634
|
const packageJsonPath = resolveNodeModulesPath(repository, "package.json");
|
|
3832
3635
|
try {
|
|
3833
|
-
if (
|
|
3636
|
+
if (existsSync12(packageJsonPath)) {
|
|
3834
3637
|
return JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
|
|
3835
3638
|
}
|
|
3836
3639
|
} catch (error) {
|
|
@@ -3861,7 +3664,7 @@ var importStrategies = [
|
|
|
3861
3664
|
provideLocalPluginGuidance(repository, context);
|
|
3862
3665
|
return null;
|
|
3863
3666
|
}
|
|
3864
|
-
if (context.localPath &&
|
|
3667
|
+
if (context.localPath && existsSync12(context.localPath)) {
|
|
3865
3668
|
logger15.info(`Loading local development plugin: ${repository}`);
|
|
3866
3669
|
return tryImporting(context.localPath, "local development plugin", repository);
|
|
3867
3670
|
}
|
|
@@ -3878,8 +3681,8 @@ var importStrategies = [
|
|
|
3878
3681
|
tryImport: async (repository) => {
|
|
3879
3682
|
if (repository.startsWith("@elizaos/plugin-")) {
|
|
3880
3683
|
const pluginName = repository.replace("@elizaos/", "");
|
|
3881
|
-
const workspacePath =
|
|
3882
|
-
if (
|
|
3684
|
+
const workspacePath = path15.resolve(process.cwd(), "..", pluginName, "dist", "index.js");
|
|
3685
|
+
if (existsSync12(workspacePath)) {
|
|
3883
3686
|
return tryImporting(workspacePath, "workspace dependency", repository);
|
|
3884
3687
|
}
|
|
3885
3688
|
}
|
|
@@ -3897,10 +3700,10 @@ var importStrategies = [
|
|
|
3897
3700
|
{
|
|
3898
3701
|
name: "global node_modules",
|
|
3899
3702
|
tryImport: async (repository) => {
|
|
3900
|
-
const globalPath =
|
|
3901
|
-
if (!
|
|
3703
|
+
const globalPath = path15.resolve(getGlobalNodeModulesPath(), repository);
|
|
3704
|
+
if (!existsSync12(path15.dirname(globalPath))) {
|
|
3902
3705
|
logger15.debug(
|
|
3903
|
-
`Global node_modules directory not found at ${
|
|
3706
|
+
`Global node_modules directory not found at ${path15.dirname(globalPath)}, skipping for ${repository}`
|
|
3904
3707
|
);
|
|
3905
3708
|
return null;
|
|
3906
3709
|
}
|
|
@@ -3962,8 +3765,8 @@ async function loadPluginModule(repository) {
|
|
|
3962
3765
|
|
|
3963
3766
|
// src/utils/package-manager.ts
|
|
3964
3767
|
import { logger as logger16 } from "@elizaos/core";
|
|
3965
|
-
import { existsSync as
|
|
3966
|
-
import
|
|
3768
|
+
import { existsSync as existsSync13 } from "fs";
|
|
3769
|
+
import path16 from "path";
|
|
3967
3770
|
import { execa as execa6 } from "execa";
|
|
3968
3771
|
async function getPackageManager() {
|
|
3969
3772
|
logger16.debug("[PackageManager] Using bun as the package manager for ElizaOS CLI");
|
|
@@ -3985,8 +3788,8 @@ function getInstallCommand(isGlobal) {
|
|
|
3985
3788
|
return ["add", ...isGlobal ? ["-g"] : []];
|
|
3986
3789
|
}
|
|
3987
3790
|
async function removeFromBunLock(packageName, directory) {
|
|
3988
|
-
const lockFilePath =
|
|
3989
|
-
if (!
|
|
3791
|
+
const lockFilePath = path16.join(directory, "bun.lock");
|
|
3792
|
+
if (!existsSync13(lockFilePath)) {
|
|
3990
3793
|
logger16.debug(`No bun.lock file found at ${lockFilePath}, skipping removal`);
|
|
3991
3794
|
return;
|
|
3992
3795
|
}
|
|
@@ -4070,10 +3873,10 @@ function getCliDirectory() {
|
|
|
4070
3873
|
try {
|
|
4071
3874
|
const cliPath = process.argv[1];
|
|
4072
3875
|
if (cliPath.includes("node_modules/@elizaos/cli")) {
|
|
4073
|
-
const cliDir =
|
|
3876
|
+
const cliDir = path17.dirname(
|
|
4074
3877
|
cliPath.split("node_modules/@elizaos/cli")[0] + "node_modules/@elizaos/cli"
|
|
4075
3878
|
);
|
|
4076
|
-
if (
|
|
3879
|
+
if (existsSync14(path17.join(cliDir, "package.json"))) {
|
|
4077
3880
|
return cliDir;
|
|
4078
3881
|
}
|
|
4079
3882
|
}
|
|
@@ -4571,7 +4374,7 @@ import {
|
|
|
4571
4374
|
logger as logger20
|
|
4572
4375
|
} from "@elizaos/core";
|
|
4573
4376
|
import * as fs9 from "fs";
|
|
4574
|
-
import * as
|
|
4377
|
+
import * as path18 from "path";
|
|
4575
4378
|
import { pathToFileURL } from "url";
|
|
4576
4379
|
var safeLogger = {
|
|
4577
4380
|
debug: logger20?.debug || console.log,
|
|
@@ -4755,14 +4558,14 @@ export const myPlugin = {
|
|
|
4755
4558
|
return;
|
|
4756
4559
|
}
|
|
4757
4560
|
try {
|
|
4758
|
-
const e2eDir =
|
|
4561
|
+
const e2eDir = path18.join(process.cwd(), "e2e");
|
|
4759
4562
|
if (!fs9.existsSync(e2eDir)) {
|
|
4760
4563
|
safeLogger.debug("No e2e directory found, skipping e2e tests");
|
|
4761
4564
|
return;
|
|
4762
4565
|
}
|
|
4763
4566
|
safeLogger.info("\nRunning e2e tests...");
|
|
4764
4567
|
const walk = (dir) => fs9.readdirSync(dir, { withFileTypes: true }).flatMap(
|
|
4765
|
-
(entry) => entry.isDirectory() ? walk(
|
|
4568
|
+
(entry) => entry.isDirectory() ? walk(path18.join(dir, entry.name)) : entry.name.match(/\.test\.(t|j)sx?$/) ? [path18.join(dir, entry.name)] : []
|
|
4766
4569
|
);
|
|
4767
4570
|
const testFiles = walk(e2eDir);
|
|
4768
4571
|
if (testFiles.length === 0) {
|
|
@@ -4770,16 +4573,16 @@ export const myPlugin = {
|
|
|
4770
4573
|
return;
|
|
4771
4574
|
}
|
|
4772
4575
|
safeLogger.info(`Found ${testFiles.length} e2e test files`);
|
|
4773
|
-
const distE2eDir =
|
|
4576
|
+
const distE2eDir = path18.join(process.cwd(), "dist", "e2e");
|
|
4774
4577
|
const hasDistE2e = fs9.existsSync(distE2eDir);
|
|
4775
4578
|
for (const testFile of testFiles) {
|
|
4776
4579
|
try {
|
|
4777
|
-
const fileName =
|
|
4778
|
-
const fileNameWithoutExt =
|
|
4580
|
+
const fileName = path18.basename(testFile);
|
|
4581
|
+
const fileNameWithoutExt = path18.basename(testFile, ".test.ts");
|
|
4779
4582
|
safeLogger.info(`Loading test file: ${fileName}`);
|
|
4780
4583
|
let moduleImportPath = testFile;
|
|
4781
4584
|
if (hasDistE2e) {
|
|
4782
|
-
const distFile =
|
|
4585
|
+
const distFile = path18.join(distE2eDir, `${fileNameWithoutExt}.test.js`);
|
|
4783
4586
|
if (fs9.existsSync(distFile)) {
|
|
4784
4587
|
moduleImportPath = distFile;
|
|
4785
4588
|
safeLogger.debug(`Using compiled version from ${distFile}`);
|
|
@@ -4856,8 +4659,8 @@ import { logger as logger21 } from "@elizaos/core";
|
|
|
4856
4659
|
import dotenv3 from "dotenv";
|
|
4857
4660
|
import { execa as execa8 } from "execa";
|
|
4858
4661
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
4859
|
-
import { existsSync as
|
|
4860
|
-
import
|
|
4662
|
+
import { existsSync as existsSync16, promises as fs10 } from "fs";
|
|
4663
|
+
import path19 from "path";
|
|
4861
4664
|
|
|
4862
4665
|
// src/utils/registry/constants.ts
|
|
4863
4666
|
var REGISTRY_ORG = "elizaos-plugins";
|
|
@@ -4868,10 +4671,10 @@ var REGISTRY_GITHUB_URL = `https://github.com/${REGISTRY_REPO}`;
|
|
|
4868
4671
|
var RAW_REGISTRY_URL = REGISTRY_URL;
|
|
4869
4672
|
|
|
4870
4673
|
// src/utils/registry/index.ts
|
|
4871
|
-
var ELIZA_DIR =
|
|
4872
|
-
var REGISTRY_SETTINGS_FILE =
|
|
4873
|
-
var ENV_FILE = resolveEnvFile() ||
|
|
4874
|
-
var REGISTRY_CACHE_FILE =
|
|
4674
|
+
var ELIZA_DIR = path19.join(process.cwd(), ".eliza");
|
|
4675
|
+
var REGISTRY_SETTINGS_FILE = path19.join(ELIZA_DIR, "registrysettings.json");
|
|
4676
|
+
var ENV_FILE = resolveEnvFile() || path19.join(ELIZA_DIR, ".env");
|
|
4677
|
+
var REGISTRY_CACHE_FILE = path19.join(ELIZA_DIR, "registry-cache.json");
|
|
4875
4678
|
var REQUIRED_ENV_VARS = ["GITHUB_TOKEN"];
|
|
4876
4679
|
var REQUIRED_SETTINGS = ["defaultRegistry"];
|
|
4877
4680
|
async function ensureElizaDir2() {
|
|
@@ -4919,13 +4722,13 @@ async function setEnvVar(key, value) {
|
|
|
4919
4722
|
async function getGitHubToken() {
|
|
4920
4723
|
try {
|
|
4921
4724
|
const envPath = resolveEnvFile();
|
|
4922
|
-
if (envPath &&
|
|
4725
|
+
if (envPath && existsSync16(envPath)) {
|
|
4923
4726
|
const envContent = await fs10.readFile(envPath, "utf-8");
|
|
4924
4727
|
const env = dotenv3.parse(envContent);
|
|
4925
4728
|
return env.GITHUB_TOKEN;
|
|
4926
4729
|
}
|
|
4927
|
-
const globalEnvPath =
|
|
4928
|
-
if (
|
|
4730
|
+
const globalEnvPath = path19.join(ELIZA_DIR, ".env");
|
|
4731
|
+
if (existsSync16(globalEnvPath) && globalEnvPath !== envPath) {
|
|
4929
4732
|
const envContent = await fs10.readFile(globalEnvPath, "utf-8");
|
|
4930
4733
|
const env = dotenv3.parse(envContent);
|
|
4931
4734
|
return env.GITHUB_TOKEN;
|
|
@@ -4942,7 +4745,7 @@ async function setGitHubToken(token) {
|
|
|
4942
4745
|
try {
|
|
4943
4746
|
let envContent = "";
|
|
4944
4747
|
try {
|
|
4945
|
-
if (
|
|
4748
|
+
if (existsSync16(ENV_FILE)) {
|
|
4946
4749
|
envContent = await fs10.readFile(ENV_FILE, "utf-8");
|
|
4947
4750
|
}
|
|
4948
4751
|
} catch (error) {
|
|
@@ -5034,7 +4837,7 @@ async function getLocalRegistryIndex() {
|
|
|
5034
4837
|
);
|
|
5035
4838
|
}
|
|
5036
4839
|
try {
|
|
5037
|
-
if (
|
|
4840
|
+
if (existsSync16(REGISTRY_CACHE_FILE)) {
|
|
5038
4841
|
const cacheContent = await fs10.readFile(REGISTRY_CACHE_FILE, "utf-8");
|
|
5039
4842
|
const cachedRegistry = JSON.parse(cacheContent);
|
|
5040
4843
|
logger21.debug("Using cached registry index");
|
|
@@ -5246,11 +5049,11 @@ async function getPackageDetails(packageName) {
|
|
|
5246
5049
|
if (response.status !== 200) {
|
|
5247
5050
|
return null;
|
|
5248
5051
|
}
|
|
5249
|
-
const
|
|
5052
|
+
const text4 = await response.text();
|
|
5250
5053
|
try {
|
|
5251
|
-
return JSON.parse(
|
|
5054
|
+
return JSON.parse(text4);
|
|
5252
5055
|
} catch {
|
|
5253
|
-
logger21.warn(`Invalid JSON response received from registry for package ${packageName}:`,
|
|
5056
|
+
logger21.warn(`Invalid JSON response received from registry for package ${packageName}:`, text4);
|
|
5254
5057
|
return null;
|
|
5255
5058
|
}
|
|
5256
5059
|
} catch (error) {
|
|
@@ -5387,21 +5190,13 @@ export {
|
|
|
5387
5190
|
promptWithNav,
|
|
5388
5191
|
promptForMultipleItems,
|
|
5389
5192
|
confirmAction,
|
|
5390
|
-
getEnvFilePath,
|
|
5391
|
-
readEnvFile,
|
|
5392
|
-
writeEnvFile,
|
|
5393
|
-
promptForEnvVars,
|
|
5394
|
-
validateEnvVars,
|
|
5395
|
-
getMissingEnvVars,
|
|
5396
|
-
validatePluginEnvVars,
|
|
5397
5193
|
getConfigFilePath,
|
|
5398
5194
|
loadConfig,
|
|
5399
5195
|
saveConfig,
|
|
5400
|
-
checkPluginRequirements,
|
|
5401
|
-
getPluginStatus,
|
|
5402
5196
|
copyDir,
|
|
5403
5197
|
copyTemplate,
|
|
5404
5198
|
copyClientDist,
|
|
5199
|
+
isRunningFromNodeModules,
|
|
5405
5200
|
getVersion,
|
|
5406
5201
|
getCliInstallTag,
|
|
5407
5202
|
isUtf8Locale,
|
|
@@ -5409,6 +5204,10 @@ export {
|
|
|
5409
5204
|
showUpdateNotification,
|
|
5410
5205
|
checkAndShowUpdateNotification,
|
|
5411
5206
|
displayBanner,
|
|
5207
|
+
createEnvFileService,
|
|
5208
|
+
getEnvFilePath,
|
|
5209
|
+
readEnvFile,
|
|
5210
|
+
writeEnvFile,
|
|
5412
5211
|
isValidPostgresUrl,
|
|
5413
5212
|
getElizaDirectories,
|
|
5414
5213
|
setupEnvFile,
|
|
@@ -5438,8 +5237,6 @@ export {
|
|
|
5438
5237
|
configSchema,
|
|
5439
5238
|
resolveConfigPaths,
|
|
5440
5239
|
loadEnvironment,
|
|
5441
|
-
mergeProcessEnvWithTemplate,
|
|
5442
|
-
formatEnvFileWithTemplate,
|
|
5443
5240
|
getPackageVersion,
|
|
5444
5241
|
getLocalPackages,
|
|
5445
5242
|
getPackageInfo,
|
|
@@ -5484,6 +5281,7 @@ export {
|
|
|
5484
5281
|
pushToGitHub,
|
|
5485
5282
|
handleError,
|
|
5486
5283
|
checkServer,
|
|
5284
|
+
getDisplayDirectory,
|
|
5487
5285
|
displayAgent,
|
|
5488
5286
|
logHeader,
|
|
5489
5287
|
detectPluginContext,
|