@elizaos/plugin-shell 2.0.0-alpha.6 → 2.0.0-alpha.7
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/actions/clearHistory.d.ts.map +1 -1
- package/dist/actions/index.d.ts +0 -2
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/generated/specs/specs.d.ts +0 -10
- package/dist/generated/specs/specs.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +143 -500
- package/dist/index.js.map +8 -9
- package/dist/providers/shellHistoryProvider.d.ts.map +1 -1
- package/dist/providers/terminalUsage.d.ts +3 -0
- package/dist/providers/terminalUsage.d.ts.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/package.json +8 -8
- package/dist/actions/executeCommand.d.ts +0 -6
- package/dist/actions/executeCommand.d.ts.map +0 -1
- package/dist/actions/processAction.d.ts +0 -7
- package/dist/actions/processAction.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
18
18
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
19
19
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
20
|
|
|
21
|
-
// node_modules/@lydell/node-pty/eventEmitter2.js
|
|
21
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/eventEmitter2.js
|
|
22
22
|
var require_eventEmitter2 = __commonJS((exports) => {
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
var EventEmitter2 = function() {
|
|
@@ -63,7 +63,7 @@ var require_eventEmitter2 = __commonJS((exports) => {
|
|
|
63
63
|
exports.EventEmitter2 = EventEmitter2;
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
// node_modules/@lydell/node-pty/terminal.js
|
|
66
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/terminal.js
|
|
67
67
|
var require_terminal = __commonJS((exports) => {
|
|
68
68
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
69
69
|
var events_1 = __require("events");
|
|
@@ -251,7 +251,7 @@ var require_terminal = __commonJS((exports) => {
|
|
|
251
251
|
exports.Terminal = Terminal;
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
-
// node_modules/@lydell/node-pty/shared/conout.js
|
|
254
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/shared/conout.js
|
|
255
255
|
var require_conout = __commonJS((exports) => {
|
|
256
256
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
257
257
|
function getWorkerPipeName(conoutPipeName) {
|
|
@@ -260,9 +260,9 @@ var require_conout = __commonJS((exports) => {
|
|
|
260
260
|
exports.getWorkerPipeName = getWorkerPipeName;
|
|
261
261
|
});
|
|
262
262
|
|
|
263
|
-
// node_modules/@lydell/node-pty/windowsConoutConnection.js
|
|
263
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/windowsConoutConnection.js
|
|
264
264
|
var require_windowsConoutConnection = __commonJS((exports) => {
|
|
265
|
-
var __dirname = "/Users/shawwalters/eliza-workspace/
|
|
265
|
+
var __dirname = "/Users/shawwalters/eliza-workspace/milady/node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty";
|
|
266
266
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
267
267
|
function adopt(value) {
|
|
268
268
|
return value instanceof P ? value : new P(function(resolve) {
|
|
@@ -435,7 +435,7 @@ var require_windowsConoutConnection = __commonJS((exports) => {
|
|
|
435
435
|
exports.ConoutConnection = ConoutConnection;
|
|
436
436
|
});
|
|
437
437
|
|
|
438
|
-
// node_modules/@lydell/node-pty/package.json
|
|
438
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/package.json
|
|
439
439
|
var require_package = __commonJS((exports, module) => {
|
|
440
440
|
module.exports = {
|
|
441
441
|
name: "@lydell/node-pty",
|
|
@@ -470,7 +470,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
470
470
|
};
|
|
471
471
|
});
|
|
472
472
|
|
|
473
|
-
// node_modules/@lydell/node-pty/requireBinary.js
|
|
473
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/requireBinary.js
|
|
474
474
|
var require_requireBinary = __commonJS((exports) => {
|
|
475
475
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
476
476
|
var PACKAGE_NAME = "@lydell/node-pty-" + process.platform + "-" + process.arch;
|
|
@@ -511,9 +511,9 @@ Your platform (` + process.platform + "-" + process.arch + ") might not be suppo
|
|
|
511
511
|
}
|
|
512
512
|
});
|
|
513
513
|
|
|
514
|
-
// node_modules/@lydell/node-pty/windowsPtyAgent.js
|
|
514
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/windowsPtyAgent.js
|
|
515
515
|
var require_windowsPtyAgent = __commonJS((exports) => {
|
|
516
|
-
var __dirname = "/Users/shawwalters/eliza-workspace/
|
|
516
|
+
var __dirname = "/Users/shawwalters/eliza-workspace/milady/node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty";
|
|
517
517
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
518
518
|
var fs5 = __require("fs");
|
|
519
519
|
var path6 = __require("path");
|
|
@@ -729,7 +729,7 @@ var require_windowsPtyAgent = __commonJS((exports) => {
|
|
|
729
729
|
}
|
|
730
730
|
});
|
|
731
731
|
|
|
732
|
-
// node_modules/@lydell/node-pty/utils.js
|
|
732
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/utils.js
|
|
733
733
|
var require_utils = __commonJS((exports) => {
|
|
734
734
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
735
735
|
function assign(target) {
|
|
@@ -747,7 +747,7 @@ var require_utils = __commonJS((exports) => {
|
|
|
747
747
|
exports.assign = assign;
|
|
748
748
|
});
|
|
749
749
|
|
|
750
|
-
// node_modules/@lydell/node-pty/windowsTerminal.js
|
|
750
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/windowsTerminal.js
|
|
751
751
|
var require_windowsTerminal = __commonJS((exports) => {
|
|
752
752
|
var __extends = exports && exports.__extends || function() {
|
|
753
753
|
var extendStatics = function(d, b) {
|
|
@@ -925,7 +925,7 @@ var require_windowsTerminal = __commonJS((exports) => {
|
|
|
925
925
|
exports.WindowsTerminal = WindowsTerminal;
|
|
926
926
|
});
|
|
927
927
|
|
|
928
|
-
// node_modules/@lydell/node-pty/unixTerminal.js
|
|
928
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/unixTerminal.js
|
|
929
929
|
var require_unixTerminal = __commonJS((exports) => {
|
|
930
930
|
var __extends = exports && exports.__extends || function() {
|
|
931
931
|
var extendStatics = function(d, b) {
|
|
@@ -1171,7 +1171,7 @@ var require_unixTerminal = __commonJS((exports) => {
|
|
|
1171
1171
|
exports.UnixTerminal = UnixTerminal;
|
|
1172
1172
|
});
|
|
1173
1173
|
|
|
1174
|
-
// node_modules/@lydell/node-pty/index.js
|
|
1174
|
+
// ../../../node_modules/.pnpm/@lydell+node-pty@1.1.0/node_modules/@lydell/node-pty/index.js
|
|
1175
1175
|
var require_node_pty = __commonJS((exports) => {
|
|
1176
1176
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1177
1177
|
var terminalCtor;
|
|
@@ -1217,26 +1217,6 @@ var coreActionsSpec = {
|
|
|
1217
1217
|
"RESET_HISTORY"
|
|
1218
1218
|
],
|
|
1219
1219
|
parameters: []
|
|
1220
|
-
},
|
|
1221
|
-
{
|
|
1222
|
-
name: "EXECUTE_COMMAND",
|
|
1223
|
-
description: "Execute shell commands including brew install, npm install, apt-get, system commands, file operations, directory navigation, and scripts.",
|
|
1224
|
-
similes: [
|
|
1225
|
-
"RUN_COMMAND",
|
|
1226
|
-
"SHELL_COMMAND",
|
|
1227
|
-
"TERMINAL_COMMAND",
|
|
1228
|
-
"EXEC",
|
|
1229
|
-
"RUN",
|
|
1230
|
-
"EXECUTE",
|
|
1231
|
-
"CREATE_FILE",
|
|
1232
|
-
"WRITE_FILE",
|
|
1233
|
-
"MAKE_FILE",
|
|
1234
|
-
"INSTALL",
|
|
1235
|
-
"BREW_INSTALL",
|
|
1236
|
-
"NPM_INSTALL",
|
|
1237
|
-
"APT_INSTALL"
|
|
1238
|
-
],
|
|
1239
|
-
parameters: []
|
|
1240
1220
|
}
|
|
1241
1221
|
]
|
|
1242
1222
|
};
|
|
@@ -1253,26 +1233,6 @@ var allActionsSpec = {
|
|
|
1253
1233
|
"RESET_HISTORY"
|
|
1254
1234
|
],
|
|
1255
1235
|
parameters: []
|
|
1256
|
-
},
|
|
1257
|
-
{
|
|
1258
|
-
name: "EXECUTE_COMMAND",
|
|
1259
|
-
description: "Execute shell commands including brew install, npm install, apt-get, system commands, file operations, directory navigation, and scripts.",
|
|
1260
|
-
similes: [
|
|
1261
|
-
"RUN_COMMAND",
|
|
1262
|
-
"SHELL_COMMAND",
|
|
1263
|
-
"TERMINAL_COMMAND",
|
|
1264
|
-
"EXEC",
|
|
1265
|
-
"RUN",
|
|
1266
|
-
"EXECUTE",
|
|
1267
|
-
"CREATE_FILE",
|
|
1268
|
-
"WRITE_FILE",
|
|
1269
|
-
"MAKE_FILE",
|
|
1270
|
-
"INSTALL",
|
|
1271
|
-
"BREW_INSTALL",
|
|
1272
|
-
"NPM_INSTALL",
|
|
1273
|
-
"APT_INSTALL"
|
|
1274
|
-
],
|
|
1275
|
-
parameters: []
|
|
1276
1236
|
}
|
|
1277
1237
|
]
|
|
1278
1238
|
};
|
|
@@ -1345,17 +1305,38 @@ var clearHistory = {
|
|
|
1345
1305
|
name: spec.name,
|
|
1346
1306
|
similes: spec.similes ? [...spec.similes] : [],
|
|
1347
1307
|
description: spec.description,
|
|
1348
|
-
validate: async (runtime, message,
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1308
|
+
validate: async (runtime, message, state, options) => {
|
|
1309
|
+
const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
|
|
1310
|
+
const __avText = __avTextRaw.toLowerCase();
|
|
1311
|
+
const __avKeywords = ["clear", "shell", "history"];
|
|
1312
|
+
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
|
|
1313
|
+
const __avRegex = new RegExp("\\b(?:clear|shell|history)\\b", "i");
|
|
1314
|
+
const __avRegexOk = __avRegex.test(__avText);
|
|
1315
|
+
const __avSource = String(message?.content?.source ?? message?.source ?? "");
|
|
1316
|
+
const __avExpectedSource = "";
|
|
1317
|
+
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
|
|
1318
|
+
const __avOptions = options && typeof options === "object" ? options : {};
|
|
1319
|
+
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
|
|
1320
|
+
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
1321
|
+
return false;
|
|
1322
|
+
}
|
|
1323
|
+
const __avLegacyValidate = async (runtime2, message2, _state) => {
|
|
1324
|
+
const shellService = runtime2.getService("shell");
|
|
1325
|
+
if (!shellService) {
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1328
|
+
const text = message2.content.text?.toLowerCase() || "";
|
|
1329
|
+
const clearKeywords = ["clear", "reset", "delete", "remove", "clean"];
|
|
1330
|
+
const historyKeywords = ["history", "terminal", "shell", "command"];
|
|
1331
|
+
const hasClearKeyword = clearKeywords.some((keyword) => text.includes(keyword));
|
|
1332
|
+
const hasHistoryKeyword = historyKeywords.some((keyword) => text.includes(keyword));
|
|
1333
|
+
return hasClearKeyword && hasHistoryKeyword;
|
|
1334
|
+
};
|
|
1335
|
+
try {
|
|
1336
|
+
return Boolean(await __avLegacyValidate(runtime, message, state, options));
|
|
1337
|
+
} catch {
|
|
1351
1338
|
return false;
|
|
1352
1339
|
}
|
|
1353
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1354
|
-
const clearKeywords = ["clear", "reset", "delete", "remove", "clean"];
|
|
1355
|
-
const historyKeywords = ["history", "terminal", "shell", "command"];
|
|
1356
|
-
const hasClearKeyword = clearKeywords.some((keyword) => text.includes(keyword));
|
|
1357
|
-
const hasHistoryKeyword = historyKeywords.some((keyword) => text.includes(keyword));
|
|
1358
|
-
return hasClearKeyword && hasHistoryKeyword;
|
|
1359
1340
|
},
|
|
1360
1341
|
handler: async (runtime, message, _state, _options, callback) => {
|
|
1361
1342
|
const shellService = runtime.getService("shell");
|
|
@@ -1392,397 +1373,12 @@ var clearHistory = {
|
|
|
1392
1373
|
},
|
|
1393
1374
|
examples: spec.examples ?? []
|
|
1394
1375
|
};
|
|
1395
|
-
// actions/executeCommand.ts
|
|
1396
|
-
import {
|
|
1397
|
-
composePromptFromState,
|
|
1398
|
-
logger as logger2,
|
|
1399
|
-
ModelType,
|
|
1400
|
-
parseJSONObjectFromText
|
|
1401
|
-
} from "@elizaos/core";
|
|
1402
|
-
var commandExtractionTemplate = `# Extracting shell command from request
|
|
1403
|
-
{{recentMessages}}
|
|
1404
|
-
|
|
1405
|
-
# Instructions: {{senderName}} wants to execute a shell command. Extract the COMPLETE shell command they want to run.
|
|
1406
|
-
|
|
1407
|
-
IMPORTANT:
|
|
1408
|
-
1. Always return the FULL executable shell command, not just the content or partial command.
|
|
1409
|
-
2. If the user mentions installing something, create the appropriate brew/npm/apt command.
|
|
1410
|
-
3. If the user directly provides a command (like "brew install X"), use it exactly as provided.
|
|
1411
|
-
4. ALWAYS extract a command if the user is asking for ANY kind of system operation.
|
|
1412
|
-
|
|
1413
|
-
Execution Options:
|
|
1414
|
-
- background: Set to true if the user asks to run it in the background or completely asynchronously.
|
|
1415
|
-
- pty: Set to true if the command is interactive (like "top", "vim", "python" shell) or requires a TTY. Defaults to TRUE for almost all commands to enable interaction.
|
|
1416
|
-
- wait: Timeout in seconds (default 30).
|
|
1417
|
-
- yield: Time in milliseconds to wait before yielding to background (default 1000). Set to 1000 (1 second) to allow quick interaction.
|
|
1418
|
-
|
|
1419
|
-
Your response must be formatted as a JSON block:
|
|
1420
|
-
\`\`\`json
|
|
1421
|
-
{
|
|
1422
|
-
"command": "<complete shell command to execute>",
|
|
1423
|
-
"background": false,
|
|
1424
|
-
"pty": true,
|
|
1425
|
-
"wait": 30,
|
|
1426
|
-
"yield": 1000
|
|
1427
|
-
}
|
|
1428
|
-
\`\`\``;
|
|
1429
|
-
var extractCommand = async (runtime, _message, state) => {
|
|
1430
|
-
const prompt = composePromptFromState({
|
|
1431
|
-
state,
|
|
1432
|
-
template: commandExtractionTemplate
|
|
1433
|
-
});
|
|
1434
|
-
for (let i = 0;i < 3; i++) {
|
|
1435
|
-
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
1436
|
-
prompt
|
|
1437
|
-
});
|
|
1438
|
-
const parsedResponse = parseJSONObjectFromText(response);
|
|
1439
|
-
if (parsedResponse?.command) {
|
|
1440
|
-
return {
|
|
1441
|
-
command: parsedResponse.command,
|
|
1442
|
-
background: parsedResponse.background === true || String(parsedResponse.background) === "true",
|
|
1443
|
-
pty: parsedResponse.pty !== false && String(parsedResponse.pty) !== "false",
|
|
1444
|
-
wait: parsedResponse.wait ? Number(parsedResponse.wait) : undefined,
|
|
1445
|
-
yield: parsedResponse.yield ? Number(parsedResponse.yield) : 1000
|
|
1446
|
-
};
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
return null;
|
|
1450
|
-
};
|
|
1451
|
-
var spec2 = requireActionSpec("EXECUTE_COMMAND");
|
|
1452
|
-
var executeCommand = {
|
|
1453
|
-
name: spec2.name,
|
|
1454
|
-
similes: spec2.similes ? [...spec2.similes] : [],
|
|
1455
|
-
description: spec2.description,
|
|
1456
|
-
validate: async (runtime, message, _state) => {
|
|
1457
|
-
const shellService = runtime.getService("shell");
|
|
1458
|
-
if (!shellService) {
|
|
1459
|
-
return false;
|
|
1460
|
-
}
|
|
1461
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1462
|
-
const commandKeywords = [
|
|
1463
|
-
"run",
|
|
1464
|
-
"execute",
|
|
1465
|
-
"command",
|
|
1466
|
-
"shell",
|
|
1467
|
-
"install",
|
|
1468
|
-
"brew",
|
|
1469
|
-
"npm",
|
|
1470
|
-
"create",
|
|
1471
|
-
"file",
|
|
1472
|
-
"directory",
|
|
1473
|
-
"folder",
|
|
1474
|
-
"list",
|
|
1475
|
-
"show",
|
|
1476
|
-
"system",
|
|
1477
|
-
"info",
|
|
1478
|
-
"check",
|
|
1479
|
-
"status",
|
|
1480
|
-
"cd",
|
|
1481
|
-
"ls",
|
|
1482
|
-
"mkdir",
|
|
1483
|
-
"echo",
|
|
1484
|
-
"cat",
|
|
1485
|
-
"touch",
|
|
1486
|
-
"git",
|
|
1487
|
-
"build",
|
|
1488
|
-
"test"
|
|
1489
|
-
];
|
|
1490
|
-
const hasCommandKeyword = commandKeywords.some((keyword) => text.includes(keyword));
|
|
1491
|
-
const hasDirectCommand = /^(brew|npm|apt|git|ls|cd|echo|cat|touch|mkdir|rm|mv|cp)\s/i.test(message.content.text || "");
|
|
1492
|
-
return hasCommandKeyword || hasDirectCommand;
|
|
1493
|
-
},
|
|
1494
|
-
handler: async (runtime, message, state, _options, callback) => {
|
|
1495
|
-
const shellService = runtime.getService("shell");
|
|
1496
|
-
if (!shellService) {
|
|
1497
|
-
if (callback) {
|
|
1498
|
-
await callback({
|
|
1499
|
-
text: "Shell service is not available.",
|
|
1500
|
-
source: message.content.source
|
|
1501
|
-
});
|
|
1502
|
-
}
|
|
1503
|
-
return { success: false, error: "Shell service is not available." };
|
|
1504
|
-
}
|
|
1505
|
-
const commandInfo = await extractCommand(runtime, message, state);
|
|
1506
|
-
if (!commandInfo?.command) {
|
|
1507
|
-
logger2.error("Failed to extract command from message:", message.content.text);
|
|
1508
|
-
if (callback) {
|
|
1509
|
-
await callback({
|
|
1510
|
-
text: "Could not determine which command to execute. Please specify a shell command.",
|
|
1511
|
-
source: message.content.source
|
|
1512
|
-
});
|
|
1513
|
-
}
|
|
1514
|
-
return { success: false, error: "Could not extract command." };
|
|
1515
|
-
}
|
|
1516
|
-
logger2.info(`Extracted command: "${commandInfo.command}"`);
|
|
1517
|
-
try {
|
|
1518
|
-
const conversationId = message.roomId || message.agentId;
|
|
1519
|
-
const result = await shellService.exec(commandInfo.command, {
|
|
1520
|
-
conversationId,
|
|
1521
|
-
background: commandInfo.background,
|
|
1522
|
-
pty: commandInfo.pty,
|
|
1523
|
-
timeout: commandInfo.wait,
|
|
1524
|
-
yieldMs: commandInfo.yield
|
|
1525
|
-
});
|
|
1526
|
-
let responseText = "";
|
|
1527
|
-
if (result.status === "running") {
|
|
1528
|
-
responseText = `Started background process (Session ID: ${result.sessionId})
|
|
1529
|
-
`;
|
|
1530
|
-
responseText += `PID: ${result.pid}
|
|
1531
|
-
`;
|
|
1532
|
-
if (result.tail) {
|
|
1533
|
-
responseText += `
|
|
1534
|
-
Output limit reached/yielded. Current tail:
|
|
1535
|
-
\`\`\`
|
|
1536
|
-
${result.tail}
|
|
1537
|
-
\`\`\``;
|
|
1538
|
-
}
|
|
1539
|
-
responseText += `
|
|
1540
|
-
Use 'check process <sessionId>' to monitor status.`;
|
|
1541
|
-
callback?.({
|
|
1542
|
-
text: responseText,
|
|
1543
|
-
source: message.content.source,
|
|
1544
|
-
action: "MANAGE_PROCESS"
|
|
1545
|
-
});
|
|
1546
|
-
return { success: true, text: responseText, data: result };
|
|
1547
|
-
}
|
|
1548
|
-
if (result.status === "completed") {
|
|
1549
|
-
responseText = `Command executed successfully (Duration: ${result.durationMs}ms)
|
|
1550
|
-
|
|
1551
|
-
`;
|
|
1552
|
-
if (result.aggregated) {
|
|
1553
|
-
responseText += `Output:
|
|
1554
|
-
\`\`\`
|
|
1555
|
-
${result.aggregated}
|
|
1556
|
-
\`\`\``;
|
|
1557
|
-
} else {
|
|
1558
|
-
responseText += "Command completed with no output.";
|
|
1559
|
-
}
|
|
1560
|
-
callback?.({
|
|
1561
|
-
text: responseText,
|
|
1562
|
-
source: message.content.source
|
|
1563
|
-
});
|
|
1564
|
-
return { success: true, text: responseText, data: result };
|
|
1565
|
-
}
|
|
1566
|
-
responseText = `Command failed (Exit Code: ${result.exitCode})
|
|
1567
|
-
`;
|
|
1568
|
-
if (result.reason) {
|
|
1569
|
-
responseText += `Reason: ${result.reason}
|
|
1570
|
-
`;
|
|
1571
|
-
}
|
|
1572
|
-
if (result.aggregated) {
|
|
1573
|
-
responseText += `
|
|
1574
|
-
Output:
|
|
1575
|
-
\`\`\`
|
|
1576
|
-
${result.aggregated}
|
|
1577
|
-
\`\`\``;
|
|
1578
|
-
}
|
|
1579
|
-
callback?.({
|
|
1580
|
-
text: responseText,
|
|
1581
|
-
source: message.content.source
|
|
1582
|
-
});
|
|
1583
|
-
return { success: false, error: responseText, data: result };
|
|
1584
|
-
} catch (error) {
|
|
1585
|
-
logger2.error("Error executing command:", error);
|
|
1586
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1587
|
-
if (callback) {
|
|
1588
|
-
await callback({
|
|
1589
|
-
text: `Failed to execute command: ${errorMessage}`,
|
|
1590
|
-
source: message.content.source
|
|
1591
|
-
});
|
|
1592
|
-
}
|
|
1593
|
-
return { success: false, error: errorMessage };
|
|
1594
|
-
}
|
|
1595
|
-
},
|
|
1596
|
-
examples: spec2.examples ?? []
|
|
1597
|
-
};
|
|
1598
|
-
// actions/processAction.ts
|
|
1599
|
-
import { composePromptFromState as composePromptFromState2, logger as logger3, ModelType as ModelType2 } from "@elizaos/core";
|
|
1600
|
-
var processActionTemplate = `You are helping extract process management parameters from user messages.
|
|
1601
|
-
|
|
1602
|
-
Recent conversation:
|
|
1603
|
-
{{recentMessages}}
|
|
1604
|
-
|
|
1605
|
-
Based on the conversation, extract the process action parameters:
|
|
1606
|
-
- action: The action to perform (list, poll, log, write, send-keys, submit, paste, kill, clear, remove)
|
|
1607
|
-
- sessionId: The session ID (required for all actions except "list")
|
|
1608
|
-
- data: Data to write (for "write" action)
|
|
1609
|
-
- keys: Array of key tokens (for "send-keys" action)
|
|
1610
|
-
- literal: Literal string to send (for "send-keys" action)
|
|
1611
|
-
- text: Text to paste (for "paste" action)
|
|
1612
|
-
- eof: Whether to close stdin after write (for "write" action)
|
|
1613
|
-
- offset: Log offset (for "log" action)
|
|
1614
|
-
- limit: Log limit (for "log" action)
|
|
1615
|
-
|
|
1616
|
-
Respond with a JSON object containing the extracted parameters:
|
|
1617
|
-
\`\`\`json
|
|
1618
|
-
{
|
|
1619
|
-
"action": "list|poll|log|write|send-keys|submit|paste|kill|clear|remove",
|
|
1620
|
-
"sessionId": "optional-session-id",
|
|
1621
|
-
"data": "optional-data",
|
|
1622
|
-
"keys": ["optional", "key", "tokens"],
|
|
1623
|
-
"literal": "optional-literal",
|
|
1624
|
-
"text": "optional-paste-text",
|
|
1625
|
-
"eof": false,
|
|
1626
|
-
"offset": 0,
|
|
1627
|
-
"limit": 100
|
|
1628
|
-
}
|
|
1629
|
-
\`\`\``;
|
|
1630
|
-
function extractJsonFromResponse(response) {
|
|
1631
|
-
const jsonMatch = response.match(/```json\s*([\s\S]*?)\s*```/);
|
|
1632
|
-
if (jsonMatch?.[1]) {
|
|
1633
|
-
try {
|
|
1634
|
-
return JSON.parse(jsonMatch[1]);
|
|
1635
|
-
} catch {}
|
|
1636
|
-
}
|
|
1637
|
-
try {
|
|
1638
|
-
const trimmed = response.trim();
|
|
1639
|
-
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
1640
|
-
return JSON.parse(trimmed);
|
|
1641
|
-
}
|
|
1642
|
-
} catch {}
|
|
1643
|
-
return null;
|
|
1644
|
-
}
|
|
1645
|
-
var processAction = {
|
|
1646
|
-
name: "MANAGE_PROCESS",
|
|
1647
|
-
similes: [
|
|
1648
|
-
"PROCESS_LIST",
|
|
1649
|
-
"PROCESS_POLL",
|
|
1650
|
-
"PROCESS_LOG",
|
|
1651
|
-
"PROCESS_WRITE",
|
|
1652
|
-
"PROCESS_KILL",
|
|
1653
|
-
"LIST_SESSIONS",
|
|
1654
|
-
"POLL_SESSION",
|
|
1655
|
-
"KILL_SESSION",
|
|
1656
|
-
"CHECK_PROCESS",
|
|
1657
|
-
"SEND_KEYS"
|
|
1658
|
-
],
|
|
1659
|
-
description: "Manage running shell/exec sessions: list, poll, log, write, send-keys, submit, paste, kill, clear, remove",
|
|
1660
|
-
validate: async (_runtime, message) => {
|
|
1661
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1662
|
-
const processKeywords = [
|
|
1663
|
-
"process",
|
|
1664
|
-
"session",
|
|
1665
|
-
"sessions",
|
|
1666
|
-
"list",
|
|
1667
|
-
"poll",
|
|
1668
|
-
"log",
|
|
1669
|
-
"write",
|
|
1670
|
-
"send-keys",
|
|
1671
|
-
"send keys",
|
|
1672
|
-
"submit",
|
|
1673
|
-
"paste",
|
|
1674
|
-
"kill",
|
|
1675
|
-
"clear",
|
|
1676
|
-
"remove",
|
|
1677
|
-
"running",
|
|
1678
|
-
"background"
|
|
1679
|
-
];
|
|
1680
|
-
const actionKeywords = [
|
|
1681
|
-
"check",
|
|
1682
|
-
"show",
|
|
1683
|
-
"get",
|
|
1684
|
-
"view",
|
|
1685
|
-
"manage",
|
|
1686
|
-
"stop",
|
|
1687
|
-
"terminate",
|
|
1688
|
-
"status"
|
|
1689
|
-
];
|
|
1690
|
-
const hasProcessKeyword = processKeywords.some((kw) => text.includes(kw));
|
|
1691
|
-
const hasActionKeyword = actionKeywords.some((kw) => text.includes(kw));
|
|
1692
|
-
return hasProcessKeyword || hasActionKeyword && text.includes("session");
|
|
1693
|
-
},
|
|
1694
|
-
handler: async (runtime, message, state) => {
|
|
1695
|
-
const shellService = runtime.getService("shell");
|
|
1696
|
-
if (!shellService) {
|
|
1697
|
-
return {
|
|
1698
|
-
success: false,
|
|
1699
|
-
text: "Shell service is not available.",
|
|
1700
|
-
error: "Shell service not found"
|
|
1701
|
-
};
|
|
1702
|
-
}
|
|
1703
|
-
const composedState = state ?? await runtime.composeState(message);
|
|
1704
|
-
const prompt = composePromptFromState2({
|
|
1705
|
-
state: composedState,
|
|
1706
|
-
template: processActionTemplate
|
|
1707
|
-
});
|
|
1708
|
-
let params = null;
|
|
1709
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1710
|
-
if (text.includes("list") && (text.includes("session") || text.includes("process"))) {
|
|
1711
|
-
params = { action: "list" };
|
|
1712
|
-
} else {
|
|
1713
|
-
try {
|
|
1714
|
-
const response = await runtime.useModel(ModelType2.TEXT_SMALL, {
|
|
1715
|
-
prompt
|
|
1716
|
-
});
|
|
1717
|
-
params = extractJsonFromResponse(String(response));
|
|
1718
|
-
} catch (error) {
|
|
1719
|
-
logger3.error("Failed to extract process parameters:", error);
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
if (!params) {
|
|
1723
|
-
params = { action: "list" };
|
|
1724
|
-
}
|
|
1725
|
-
const result = await shellService.processAction(params);
|
|
1726
|
-
return {
|
|
1727
|
-
success: result.success,
|
|
1728
|
-
text: result.message
|
|
1729
|
-
};
|
|
1730
|
-
},
|
|
1731
|
-
examples: [
|
|
1732
|
-
[
|
|
1733
|
-
{
|
|
1734
|
-
name: "{{user1}}",
|
|
1735
|
-
content: { text: "List all running processes" }
|
|
1736
|
-
},
|
|
1737
|
-
{
|
|
1738
|
-
name: "{{agentName}}",
|
|
1739
|
-
content: {
|
|
1740
|
-
text: `Here are the running sessions:
|
|
1741
|
-
calm-harbor running 5m30s :: npm install
|
|
1742
|
-
brisk-reef completed 2m15s :: git status`,
|
|
1743
|
-
action: "MANAGE_PROCESS"
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
],
|
|
1747
|
-
[
|
|
1748
|
-
{
|
|
1749
|
-
name: "{{user1}}",
|
|
1750
|
-
content: { text: "Check the status of session calm-harbor" }
|
|
1751
|
-
},
|
|
1752
|
-
{
|
|
1753
|
-
name: "{{agentName}}",
|
|
1754
|
-
content: {
|
|
1755
|
-
text: `Session calm-harbor is still running.
|
|
1756
|
-
|
|
1757
|
-
Output:
|
|
1758
|
-
npm WARN deprecated...
|
|
1759
|
-
|
|
1760
|
-
Process still running.`,
|
|
1761
|
-
action: "MANAGE_PROCESS"
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
],
|
|
1765
|
-
[
|
|
1766
|
-
{
|
|
1767
|
-
name: "{{user1}}",
|
|
1768
|
-
content: { text: "Kill the session brisk-reef" }
|
|
1769
|
-
},
|
|
1770
|
-
{
|
|
1771
|
-
name: "{{agentName}}",
|
|
1772
|
-
content: {
|
|
1773
|
-
text: "Killed session brisk-reef.",
|
|
1774
|
-
action: "MANAGE_PROCESS"
|
|
1775
|
-
}
|
|
1776
|
-
}
|
|
1777
|
-
]
|
|
1778
|
-
]
|
|
1779
|
-
};
|
|
1780
1376
|
// approvals/allowlist.ts
|
|
1781
1377
|
import crypto2 from "node:crypto";
|
|
1782
1378
|
import fs from "node:fs";
|
|
1783
1379
|
import os from "node:os";
|
|
1784
1380
|
import path from "node:path";
|
|
1785
|
-
import { logger as
|
|
1381
|
+
import { logger as logger2 } from "@elizaos/core";
|
|
1786
1382
|
|
|
1787
1383
|
// approvals/types.ts
|
|
1788
1384
|
var DEFAULT_SAFE_BINS = [
|
|
@@ -1920,12 +1516,12 @@ function readApprovalsSnapshot() {
|
|
|
1920
1516
|
try {
|
|
1921
1517
|
parsed = JSON.parse(raw);
|
|
1922
1518
|
} catch (parseError) {
|
|
1923
|
-
|
|
1519
|
+
logger2.warn({ src: "exec-approval", parseError, filePath }, "Failed to parse approval config snapshot - file may be corrupted");
|
|
1924
1520
|
parsed = null;
|
|
1925
1521
|
}
|
|
1926
1522
|
const file = parsed?.version === 1 ? normalizeApprovals(parsed) : normalizeApprovals({ version: 1, agents: {} });
|
|
1927
1523
|
if (parsed && parsed.version !== 1) {
|
|
1928
|
-
|
|
1524
|
+
logger2.warn({ src: "exec-approval", version: parsed.version, filePath }, "Approval config snapshot has unexpected version");
|
|
1929
1525
|
}
|
|
1930
1526
|
return {
|
|
1931
1527
|
path: filePath,
|
|
@@ -1939,7 +1535,7 @@ function loadApprovals() {
|
|
|
1939
1535
|
const filePath = getApprovalFilePath();
|
|
1940
1536
|
try {
|
|
1941
1537
|
if (!fs.existsSync(filePath)) {
|
|
1942
|
-
|
|
1538
|
+
logger2.debug({ src: "exec-approval", filePath }, "Approval config file does not exist, using defaults");
|
|
1943
1539
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1944
1540
|
}
|
|
1945
1541
|
const raw = fs.readFileSync(filePath, "utf8");
|
|
@@ -1947,16 +1543,16 @@ function loadApprovals() {
|
|
|
1947
1543
|
try {
|
|
1948
1544
|
parsed = JSON.parse(raw);
|
|
1949
1545
|
} catch (parseError) {
|
|
1950
|
-
|
|
1546
|
+
logger2.error({ src: "exec-approval", parseError, filePath }, "Failed to parse approval config JSON - file may be corrupted. Using defaults.");
|
|
1951
1547
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1952
1548
|
}
|
|
1953
1549
|
if (parsed?.version !== 1) {
|
|
1954
|
-
|
|
1550
|
+
logger2.warn({ src: "exec-approval", version: parsed?.version, filePath }, "Approval config has unexpected version, using defaults");
|
|
1955
1551
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1956
1552
|
}
|
|
1957
1553
|
return normalizeApprovals(parsed);
|
|
1958
1554
|
} catch (error) {
|
|
1959
|
-
|
|
1555
|
+
logger2.error({ src: "exec-approval", error, filePath }, "Failed to load approval config - using defaults. This may indicate a permissions issue.");
|
|
1960
1556
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1961
1557
|
}
|
|
1962
1558
|
}
|
|
@@ -1972,7 +1568,7 @@ function saveApprovals(file) {
|
|
|
1972
1568
|
fs.chmodSync(filePath, 384);
|
|
1973
1569
|
} catch {}
|
|
1974
1570
|
} catch (error) {
|
|
1975
|
-
|
|
1571
|
+
logger2.error({ src: "exec-approval", error, filePath }, "Failed to save approval configuration");
|
|
1976
1572
|
throw new Error(`Failed to save approval configuration to ${filePath}: ${error}`);
|
|
1977
1573
|
}
|
|
1978
1574
|
}
|
|
@@ -1991,7 +1587,7 @@ function ensureApprovals() {
|
|
|
1991
1587
|
try {
|
|
1992
1588
|
saveApprovals(updated);
|
|
1993
1589
|
} catch (error) {
|
|
1994
|
-
|
|
1590
|
+
logger2.warn({ src: "exec-approval", error }, "Failed to save approval config during ensureApprovals - " + "returning in-memory config. Changes will not persist.");
|
|
1995
1591
|
throw error;
|
|
1996
1592
|
}
|
|
1997
1593
|
return updated;
|
|
@@ -2013,7 +1609,7 @@ function resolveApprovals(agentId, overrides) {
|
|
|
2013
1609
|
try {
|
|
2014
1610
|
file = ensureApprovals();
|
|
2015
1611
|
} catch (error) {
|
|
2016
|
-
|
|
1612
|
+
logger2.warn({ src: "exec-approval", error }, "Could not ensure approval config exists - using read-only config");
|
|
2017
1613
|
file = loadApprovals();
|
|
2018
1614
|
}
|
|
2019
1615
|
return resolveApprovalsFromFile({
|
|
@@ -2155,7 +1751,7 @@ function recordAllowlistUse(approvals, agentId, entry, command, resolvedPath) {
|
|
|
2155
1751
|
saveApprovals(approvals);
|
|
2156
1752
|
return true;
|
|
2157
1753
|
} catch (error) {
|
|
2158
|
-
|
|
1754
|
+
logger2.warn({ src: "exec-approval", error, pattern: entry.pattern }, "Failed to record allowlist usage - continuing without update");
|
|
2159
1755
|
return false;
|
|
2160
1756
|
}
|
|
2161
1757
|
}
|
|
@@ -2166,11 +1762,11 @@ function addAllowlistEntry(approvals, agentId, pattern) {
|
|
|
2166
1762
|
const allowlist = Array.isArray(existing.allowlist) ? existing.allowlist : [];
|
|
2167
1763
|
const trimmed = pattern.trim();
|
|
2168
1764
|
if (!trimmed) {
|
|
2169
|
-
|
|
1765
|
+
logger2.warn({ src: "exec-approval" }, "Attempted to add empty pattern to allowlist");
|
|
2170
1766
|
return false;
|
|
2171
1767
|
}
|
|
2172
1768
|
if (allowlist.some((entry) => entry.pattern === trimmed)) {
|
|
2173
|
-
|
|
1769
|
+
logger2.debug({ src: "exec-approval", pattern: trimmed }, "Pattern already in allowlist");
|
|
2174
1770
|
return false;
|
|
2175
1771
|
}
|
|
2176
1772
|
allowlist.push({
|
|
@@ -2182,10 +1778,10 @@ function addAllowlistEntry(approvals, agentId, pattern) {
|
|
|
2182
1778
|
approvals.agents = agents;
|
|
2183
1779
|
try {
|
|
2184
1780
|
saveApprovals(approvals);
|
|
2185
|
-
|
|
1781
|
+
logger2.info({ src: "exec-approval", pattern: trimmed, agentId: target }, "Added pattern to allowlist");
|
|
2186
1782
|
return true;
|
|
2187
1783
|
} catch (error) {
|
|
2188
|
-
|
|
1784
|
+
logger2.error({ src: "exec-approval", error, pattern: trimmed }, "Failed to save allowlist after adding entry");
|
|
2189
1785
|
return false;
|
|
2190
1786
|
}
|
|
2191
1787
|
}
|
|
@@ -2902,7 +2498,7 @@ function requiresExecApproval(params) {
|
|
|
2902
2498
|
return params.ask === "always" || params.ask === "on-miss" && params.security === "allowlist" && (!params.analysisOk || !params.allowlistSatisfied);
|
|
2903
2499
|
}
|
|
2904
2500
|
// approvals/service.ts
|
|
2905
|
-
import { logger as
|
|
2501
|
+
import { logger as logger3, Service } from "@elizaos/core";
|
|
2906
2502
|
var EXEC_APPROVAL_OPTIONS = [
|
|
2907
2503
|
{ name: "allow-once", description: "Allow this one time" },
|
|
2908
2504
|
{ name: "allow-always", description: "Always allow this" },
|
|
@@ -2925,7 +2521,7 @@ class ExecApprovalService extends Service {
|
|
|
2925
2521
|
try {
|
|
2926
2522
|
service.approvalConfig = resolveApprovals(runtime.agentId);
|
|
2927
2523
|
} catch (error) {
|
|
2928
|
-
|
|
2524
|
+
logger3.error({ src: "service:exec_approval", error, agentId: runtime.agentId }, "Failed to load approval config during startup - using in-memory defaults. " + "Approvals may not persist. Check file permissions for ~/.eliza/exec-approvals.json");
|
|
2929
2525
|
service.approvalConfig = {
|
|
2930
2526
|
path: "",
|
|
2931
2527
|
socketPath: "",
|
|
@@ -2946,11 +2542,11 @@ class ExecApprovalService extends Service {
|
|
|
2946
2542
|
file: { version: 1, agents: {} }
|
|
2947
2543
|
};
|
|
2948
2544
|
}
|
|
2949
|
-
|
|
2545
|
+
logger3.info({ src: "service:exec_approval", agentId: runtime.agentId }, "ExecApprovalService started");
|
|
2950
2546
|
return service;
|
|
2951
2547
|
}
|
|
2952
2548
|
async stop() {
|
|
2953
|
-
|
|
2549
|
+
logger3.debug({ src: "service:exec_approval" }, "ExecApprovalService stopped");
|
|
2954
2550
|
}
|
|
2955
2551
|
loadConfig(agentId) {
|
|
2956
2552
|
this.approvalConfig = resolveApprovals(agentId ?? this.runtime?.agentId);
|
|
@@ -3022,7 +2618,7 @@ class ExecApprovalService extends Service {
|
|
|
3022
2618
|
}
|
|
3023
2619
|
}
|
|
3024
2620
|
if (recordingFailed) {
|
|
3025
|
-
|
|
2621
|
+
logger3.debug({ src: "service:exec_approval", command: params.command }, "Some allowlist usage records failed to save - command will still proceed");
|
|
3026
2622
|
}
|
|
3027
2623
|
return {
|
|
3028
2624
|
allowed: true,
|
|
@@ -3078,7 +2674,7 @@ class ExecApprovalService extends Service {
|
|
|
3078
2674
|
async requestApproval(request) {
|
|
3079
2675
|
const approvalService = this.runtime?.getService("approval");
|
|
3080
2676
|
if (!approvalService) {
|
|
3081
|
-
|
|
2677
|
+
logger3.warn({ src: "service:exec_approval" }, "ApprovalService not available, denying by default");
|
|
3082
2678
|
return {
|
|
3083
2679
|
decision: "deny",
|
|
3084
2680
|
timedOut: false
|
|
@@ -3130,7 +2726,7 @@ class ExecApprovalService extends Service {
|
|
|
3130
2726
|
async requestApprovalAsync(request, callbacks) {
|
|
3131
2727
|
const approvalService = this.runtime?.getService("approval");
|
|
3132
2728
|
if (!approvalService) {
|
|
3133
|
-
|
|
2729
|
+
logger3.warn({ src: "service:exec_approval" }, "ApprovalService not available");
|
|
3134
2730
|
if (callbacks?.onDenied) {
|
|
3135
2731
|
await callbacks.onDenied();
|
|
3136
2732
|
}
|
|
@@ -3205,7 +2801,7 @@ class ExecApprovalService extends Service {
|
|
|
3205
2801
|
}
|
|
3206
2802
|
async getPendingApprovals(roomId) {
|
|
3207
2803
|
if (!this.runtime) {
|
|
3208
|
-
|
|
2804
|
+
logger3.warn({ src: "service:exec_approval" }, "Cannot get pending approvals - runtime not available");
|
|
3209
2805
|
return [];
|
|
3210
2806
|
}
|
|
3211
2807
|
try {
|
|
@@ -3229,7 +2825,7 @@ class ExecApprovalService extends Service {
|
|
|
3229
2825
|
};
|
|
3230
2826
|
});
|
|
3231
2827
|
} catch (error) {
|
|
3232
|
-
|
|
2828
|
+
logger3.error({ src: "service:exec_approval", error, roomId }, "Failed to get pending approvals");
|
|
3233
2829
|
return [];
|
|
3234
2830
|
}
|
|
3235
2831
|
}
|
|
@@ -3247,19 +2843,20 @@ function mapOptionToDecision(option) {
|
|
|
3247
2843
|
// providers/shellHistoryProvider.ts
|
|
3248
2844
|
import {
|
|
3249
2845
|
addHeader,
|
|
3250
|
-
logger as
|
|
2846
|
+
logger as logger4
|
|
3251
2847
|
} from "@elizaos/core";
|
|
3252
2848
|
var MAX_OUTPUT_LENGTH = 8000;
|
|
3253
2849
|
var TRUNCATE_SEGMENT_LENGTH = 4000;
|
|
3254
|
-
var
|
|
2850
|
+
var spec2 = requireProviderSpec("SHELL_HISTORY");
|
|
3255
2851
|
var shellHistoryProvider = {
|
|
3256
|
-
name:
|
|
2852
|
+
name: spec2.name,
|
|
3257
2853
|
description: "Provides recent shell command history, current working directory, and file operations within the restricted environment",
|
|
3258
2854
|
position: 99,
|
|
2855
|
+
dynamic: true,
|
|
3259
2856
|
get: async (runtime, message, _state) => {
|
|
3260
2857
|
const shellService = runtime.getService("shell");
|
|
3261
2858
|
if (!shellService) {
|
|
3262
|
-
|
|
2859
|
+
logger4.warn("[shellHistoryProvider] Shell service not found");
|
|
3263
2860
|
return {
|
|
3264
2861
|
values: {
|
|
3265
2862
|
shellHistory: "Shell service is not available",
|
|
@@ -3359,15 +2956,62 @@ ${addHeader("# Shell History (Last 10)", historyText)}${fileOpsText}`;
|
|
|
3359
2956
|
};
|
|
3360
2957
|
}
|
|
3361
2958
|
};
|
|
2959
|
+
// providers/terminalUsage.ts
|
|
2960
|
+
import { validateActionKeywords, validateActionRegex } from "@elizaos/core";
|
|
2961
|
+
var terminalUsageProvider = {
|
|
2962
|
+
name: "terminalUsage",
|
|
2963
|
+
description: "Terminal usage instructions",
|
|
2964
|
+
dynamic: true,
|
|
2965
|
+
relevanceKeywords: [
|
|
2966
|
+
"terminalusage",
|
|
2967
|
+
"terminalusageprovider",
|
|
2968
|
+
"plugin",
|
|
2969
|
+
"shell",
|
|
2970
|
+
"status",
|
|
2971
|
+
"state",
|
|
2972
|
+
"context",
|
|
2973
|
+
"info",
|
|
2974
|
+
"details",
|
|
2975
|
+
"chat",
|
|
2976
|
+
"conversation",
|
|
2977
|
+
"agent",
|
|
2978
|
+
"room",
|
|
2979
|
+
"channel"
|
|
2980
|
+
],
|
|
2981
|
+
get: async (_runtime, _message, _state) => {
|
|
2982
|
+
const __providerKeywords = ["terminalusage", "terminalusageprovider", "plugin", "shell", "status", "state", "context", "info", "details", "chat", "conversation", "agent", "room", "channel"];
|
|
2983
|
+
const __providerRegex = new RegExp(`\\b(${__providerKeywords.join("|")})\\b`, "i");
|
|
2984
|
+
const __recentMessages = _state?.recentMessagesData || [];
|
|
2985
|
+
const __isRelevant = validateActionKeywords(_message, __recentMessages, __providerKeywords) || validateActionRegex(_message, __recentMessages, __providerRegex);
|
|
2986
|
+
if (!__isRelevant) {
|
|
2987
|
+
return { text: "" };
|
|
2988
|
+
}
|
|
2989
|
+
const settings = _runtime.character?.settings;
|
|
2990
|
+
if (settings?.DISABLE_TERMINAL) {
|
|
2991
|
+
return { text: "" };
|
|
2992
|
+
}
|
|
2993
|
+
return {
|
|
2994
|
+
text: [
|
|
2995
|
+
"## Terminal",
|
|
2996
|
+
"",
|
|
2997
|
+
"You can run shell commands in the user's embedded terminal using the RUN_IN_TERMINAL action.",
|
|
2998
|
+
"Use this when the user asks you to run a command, execute a script, install packages, etc.",
|
|
2999
|
+
"The terminal auto-opens and shows the command output in real time."
|
|
3000
|
+
].join(`
|
|
3001
|
+
`)
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3362
3006
|
// services/shellService.ts
|
|
3363
3007
|
import path6 from "node:path";
|
|
3364
|
-
import { logger as
|
|
3008
|
+
import { logger as logger7, Service as Service2 } from "@elizaos/core";
|
|
3365
3009
|
import spawn2 from "cross-spawn";
|
|
3366
3010
|
|
|
3367
3011
|
// utils/config.ts
|
|
3368
3012
|
import fs3 from "node:fs";
|
|
3369
3013
|
import path3 from "node:path";
|
|
3370
|
-
import { logger as
|
|
3014
|
+
import { logger as logger5 } from "@elizaos/core";
|
|
3371
3015
|
import { z } from "zod";
|
|
3372
3016
|
var configSchema = z.object({
|
|
3373
3017
|
enabled: z.boolean(),
|
|
@@ -3438,7 +3082,7 @@ function loadShellConfig() {
|
|
|
3438
3082
|
throw new Error(`SHELL_ALLOWED_DIRECTORY is not a directory: ${allowedDirectory}`);
|
|
3439
3083
|
}
|
|
3440
3084
|
config.allowedDirectory = path3.resolve(allowedDirectory);
|
|
3441
|
-
|
|
3085
|
+
logger5.info(`Shell plugin enabled with allowed directory: ${config.allowedDirectory}, ` + `background: ${allowBackground}, timeout: ${timeout}ms`);
|
|
3442
3086
|
} catch (error) {
|
|
3443
3087
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
3444
3088
|
throw new Error(`SHELL_ALLOWED_DIRECTORY does not exist: ${allowedDirectory}`);
|
|
@@ -3449,13 +3093,13 @@ function loadShellConfig() {
|
|
|
3449
3093
|
}
|
|
3450
3094
|
// utils/pathUtils.ts
|
|
3451
3095
|
import path4 from "node:path";
|
|
3452
|
-
import { logger as
|
|
3096
|
+
import { logger as logger6 } from "@elizaos/core";
|
|
3453
3097
|
function validatePath(commandPath, allowedDir, currentDir) {
|
|
3454
3098
|
const resolvedPath = path4.resolve(currentDir, commandPath);
|
|
3455
3099
|
const normalizedPath = path4.normalize(resolvedPath);
|
|
3456
3100
|
const normalizedAllowed = path4.normalize(allowedDir);
|
|
3457
3101
|
if (!normalizedPath.startsWith(normalizedAllowed)) {
|
|
3458
|
-
|
|
3102
|
+
logger6.warn(`Path validation failed: ${normalizedPath} is outside allowed directory ${normalizedAllowed}`);
|
|
3459
3103
|
return null;
|
|
3460
3104
|
}
|
|
3461
3105
|
return normalizedPath;
|
|
@@ -3472,19 +3116,19 @@ function isSafeCommand(command) {
|
|
|
3472
3116
|
];
|
|
3473
3117
|
for (const pattern of pathTraversalPatterns) {
|
|
3474
3118
|
if (pattern.test(command)) {
|
|
3475
|
-
|
|
3119
|
+
logger6.warn(`Path traversal detected in command: ${command}`);
|
|
3476
3120
|
return false;
|
|
3477
3121
|
}
|
|
3478
3122
|
}
|
|
3479
3123
|
for (const pattern of dangerousPatterns) {
|
|
3480
3124
|
if (pattern.test(command)) {
|
|
3481
|
-
|
|
3125
|
+
logger6.warn(`Dangerous pattern detected in command: ${command}`);
|
|
3482
3126
|
return false;
|
|
3483
3127
|
}
|
|
3484
3128
|
}
|
|
3485
3129
|
const pipeCount = (command.match(/\|/g) || []).length;
|
|
3486
3130
|
if (pipeCount > 1) {
|
|
3487
|
-
|
|
3131
|
+
logger6.warn(`Multiple pipes detected in command: ${command}`);
|
|
3488
3132
|
return false;
|
|
3489
3133
|
}
|
|
3490
3134
|
return true;
|
|
@@ -4440,7 +4084,7 @@ class ShellService extends Service2 {
|
|
|
4440
4084
|
}
|
|
4441
4085
|
static async start(runtime) {
|
|
4442
4086
|
const instance = new ShellService(runtime);
|
|
4443
|
-
|
|
4087
|
+
logger7.info("Shell service initialized with PTY, background execution, and history tracking");
|
|
4444
4088
|
return instance;
|
|
4445
4089
|
}
|
|
4446
4090
|
async stop() {
|
|
@@ -4448,13 +4092,13 @@ class ShellService extends Service2 {
|
|
|
4448
4092
|
for (const session of runningSessions2) {
|
|
4449
4093
|
try {
|
|
4450
4094
|
killSession(session);
|
|
4451
|
-
|
|
4095
|
+
logger7.debug(`Killed shell session: ${session.id}`);
|
|
4452
4096
|
} catch (err) {
|
|
4453
|
-
|
|
4097
|
+
logger7.warn(`Failed to kill shell session ${session.id}: ${err}`);
|
|
4454
4098
|
}
|
|
4455
4099
|
}
|
|
4456
4100
|
this.commandHistory.clear();
|
|
4457
|
-
|
|
4101
|
+
logger7.info(`Shell service stopped, cleaned up ${runningSessions2.length} running sessions`);
|
|
4458
4102
|
}
|
|
4459
4103
|
get capabilityDescription() {
|
|
4460
4104
|
return "Execute shell commands with PTY support, background execution, and session management";
|
|
@@ -4476,7 +4120,7 @@ class ShellService extends Service2 {
|
|
|
4476
4120
|
if (this.runtime && this.runtime.sandboxMode) {
|
|
4477
4121
|
const hostApiUrl = this.runtime.getSetting("SANDBOX_HOST_API_URL") ?? "http://localhost:2138";
|
|
4478
4122
|
const runtimeFetch = this.runtime.fetch ?? globalThis.fetch;
|
|
4479
|
-
|
|
4123
|
+
logger7.info(`[shell:sandbox] routing exec to ${hostApiUrl}: ${command.substring(0, 100)}`);
|
|
4480
4124
|
try {
|
|
4481
4125
|
const response = await runtimeFetch(`${hostApiUrl}/api/sandbox/exec`, {
|
|
4482
4126
|
method: "POST",
|
|
@@ -4488,7 +4132,7 @@ class ShellService extends Service2 {
|
|
|
4488
4132
|
})
|
|
4489
4133
|
});
|
|
4490
4134
|
const result2 = await response.json();
|
|
4491
|
-
|
|
4135
|
+
logger7.info(`[shell:sandbox] exec completed: exit=${result2.exitCode} duration=${result2.durationMs}ms`);
|
|
4492
4136
|
return {
|
|
4493
4137
|
success: result2.exitCode === 0,
|
|
4494
4138
|
stdout: result2.stdout,
|
|
@@ -4498,7 +4142,7 @@ class ShellService extends Service2 {
|
|
|
4498
4142
|
};
|
|
4499
4143
|
} catch (err) {
|
|
4500
4144
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
4501
|
-
|
|
4145
|
+
logger7.error(`[shell:sandbox] exec failed: ${errMsg}`);
|
|
4502
4146
|
return {
|
|
4503
4147
|
success: false,
|
|
4504
4148
|
stdout: "",
|
|
@@ -5110,7 +4754,7 @@ Warnings:
|
|
|
5110
4754
|
}
|
|
5111
4755
|
clearCommandHistory(conversationId) {
|
|
5112
4756
|
this.commandHistory.delete(conversationId);
|
|
5113
|
-
|
|
4757
|
+
logger7.info(`Cleared command history for conversation: ${conversationId}`);
|
|
5114
4758
|
}
|
|
5115
4759
|
getCurrentDirectory(_conversationId) {
|
|
5116
4760
|
return this.currentDirectory;
|
|
@@ -5170,12 +4814,12 @@ Warnings:
|
|
|
5170
4814
|
if (useShell) {
|
|
5171
4815
|
cmd = "sh";
|
|
5172
4816
|
args = ["-c", command];
|
|
5173
|
-
|
|
4817
|
+
logger7.info(`Executing shell command: sh -c "${command}" in ${this.currentDirectory}`);
|
|
5174
4818
|
} else {
|
|
5175
4819
|
const parts = command.split(/\s+/);
|
|
5176
4820
|
cmd = parts[0];
|
|
5177
4821
|
args = parts.slice(1);
|
|
5178
|
-
|
|
4822
|
+
logger7.info(`Executing command: ${cmd} ${args.join(" ")} in ${this.currentDirectory}`);
|
|
5179
4823
|
}
|
|
5180
4824
|
let stdout = "";
|
|
5181
4825
|
let stderr = "";
|
|
@@ -5280,7 +4924,7 @@ Command timed out`,
|
|
|
5280
4924
|
} catch (err) {
|
|
5281
4925
|
const errText = String(err);
|
|
5282
4926
|
const warning = `Warning: PTY spawn failed (${errText}); retrying without PTY.`;
|
|
5283
|
-
|
|
4927
|
+
logger7.warn(`exec: PTY spawn failed (${errText}); retrying without PTY.`);
|
|
5284
4928
|
opts.warnings.push(warning);
|
|
5285
4929
|
}
|
|
5286
4930
|
}
|
|
@@ -5569,16 +5213,17 @@ ${String(err)}` : String(err);
|
|
|
5569
5213
|
// index.ts
|
|
5570
5214
|
var shellPlugin = {
|
|
5571
5215
|
name: "shell",
|
|
5572
|
-
description: "
|
|
5216
|
+
description: "Shell observability and history management providers",
|
|
5573
5217
|
services: [ShellService, ExecApprovalService],
|
|
5574
|
-
actions: [
|
|
5575
|
-
providers: [shellHistoryProvider]
|
|
5218
|
+
actions: [clearHistory],
|
|
5219
|
+
providers: [shellHistoryProvider, terminalUsageProvider]
|
|
5576
5220
|
};
|
|
5577
5221
|
var typescript_default = shellPlugin;
|
|
5578
5222
|
export {
|
|
5579
5223
|
validatePath,
|
|
5580
5224
|
truncateMiddle,
|
|
5581
5225
|
trimWithCap,
|
|
5226
|
+
terminalUsageProvider,
|
|
5582
5227
|
tail,
|
|
5583
5228
|
stripDsrRequests,
|
|
5584
5229
|
spawnWithFallback,
|
|
@@ -5600,7 +5245,6 @@ export {
|
|
|
5600
5245
|
recordAllowlistUse,
|
|
5601
5246
|
readEnvInt,
|
|
5602
5247
|
readApprovalsSnapshot,
|
|
5603
|
-
processAction,
|
|
5604
5248
|
pad,
|
|
5605
5249
|
normalizeSafeBins,
|
|
5606
5250
|
normalizeApprovals,
|
|
@@ -5626,7 +5270,6 @@ export {
|
|
|
5626
5270
|
formatSpawnError,
|
|
5627
5271
|
formatDuration,
|
|
5628
5272
|
extractBaseCommand,
|
|
5629
|
-
executeCommand,
|
|
5630
5273
|
evaluateShellAllowlist,
|
|
5631
5274
|
evaluateExecAllowlist,
|
|
5632
5275
|
ensureApprovals,
|
|
@@ -5656,4 +5299,4 @@ export {
|
|
|
5656
5299
|
BRACKETED_PASTE_END
|
|
5657
5300
|
};
|
|
5658
5301
|
|
|
5659
|
-
//# debugId=
|
|
5302
|
+
//# debugId=EB43D3D65D87A50A64756E2164756E21
|