@elizaos/plugin-shell 2.0.0-alpha.5 → 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/approvals/allowlist.d.ts.map +1 -1
- package/dist/approvals/analysis.d.ts.map +1 -1
- package/dist/approvals/index.d.ts.map +1 -1
- package/dist/approvals/service.d.ts.map +1 -1
- package/dist/approvals/types.d.ts.map +1 -1
- package/dist/generated/specs/spec-helpers.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.browser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +205 -501
- package/dist/index.js.map +19 -21
- 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/services/index.d.ts.map +1 -1
- package/dist/services/processRegistry.d.ts.map +1 -1
- package/dist/services/shellService.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/pathUtils.d.ts.map +1 -1
- package/dist/utils/processQueue.d.ts.map +1 -1
- package/dist/utils/ptyKeys.d.ts.map +1 -1
- package/dist/utils/shellUtils.d.ts.map +1 -1
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/package.json +124 -124
- 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;
|
|
@@ -1210,26 +1210,11 @@ var coreActionsSpec = {
|
|
|
1210
1210
|
{
|
|
1211
1211
|
name: "CLEAR_SHELL_HISTORY",
|
|
1212
1212
|
description: "Clears the recorded history of shell commands for the current conversation",
|
|
1213
|
-
similes: ["RESET_SHELL", "CLEAR_TERMINAL", "CLEAR_HISTORY", "RESET_HISTORY"],
|
|
1214
|
-
parameters: []
|
|
1215
|
-
},
|
|
1216
|
-
{
|
|
1217
|
-
name: "EXECUTE_COMMAND",
|
|
1218
|
-
description: "Execute shell commands including brew install, npm install, apt-get, system commands, file operations, directory navigation, and scripts.",
|
|
1219
1213
|
similes: [
|
|
1220
|
-
"
|
|
1221
|
-
"
|
|
1222
|
-
"
|
|
1223
|
-
"
|
|
1224
|
-
"RUN",
|
|
1225
|
-
"EXECUTE",
|
|
1226
|
-
"CREATE_FILE",
|
|
1227
|
-
"WRITE_FILE",
|
|
1228
|
-
"MAKE_FILE",
|
|
1229
|
-
"INSTALL",
|
|
1230
|
-
"BREW_INSTALL",
|
|
1231
|
-
"NPM_INSTALL",
|
|
1232
|
-
"APT_INSTALL"
|
|
1214
|
+
"RESET_SHELL",
|
|
1215
|
+
"CLEAR_TERMINAL",
|
|
1216
|
+
"CLEAR_HISTORY",
|
|
1217
|
+
"RESET_HISTORY"
|
|
1233
1218
|
],
|
|
1234
1219
|
parameters: []
|
|
1235
1220
|
}
|
|
@@ -1241,26 +1226,11 @@ var allActionsSpec = {
|
|
|
1241
1226
|
{
|
|
1242
1227
|
name: "CLEAR_SHELL_HISTORY",
|
|
1243
1228
|
description: "Clears the recorded history of shell commands for the current conversation",
|
|
1244
|
-
similes: ["RESET_SHELL", "CLEAR_TERMINAL", "CLEAR_HISTORY", "RESET_HISTORY"],
|
|
1245
|
-
parameters: []
|
|
1246
|
-
},
|
|
1247
|
-
{
|
|
1248
|
-
name: "EXECUTE_COMMAND",
|
|
1249
|
-
description: "Execute shell commands including brew install, npm install, apt-get, system commands, file operations, directory navigation, and scripts.",
|
|
1250
1229
|
similes: [
|
|
1251
|
-
"
|
|
1252
|
-
"
|
|
1253
|
-
"
|
|
1254
|
-
"
|
|
1255
|
-
"RUN",
|
|
1256
|
-
"EXECUTE",
|
|
1257
|
-
"CREATE_FILE",
|
|
1258
|
-
"WRITE_FILE",
|
|
1259
|
-
"MAKE_FILE",
|
|
1260
|
-
"INSTALL",
|
|
1261
|
-
"BREW_INSTALL",
|
|
1262
|
-
"NPM_INSTALL",
|
|
1263
|
-
"APT_INSTALL"
|
|
1230
|
+
"RESET_SHELL",
|
|
1231
|
+
"CLEAR_TERMINAL",
|
|
1232
|
+
"CLEAR_HISTORY",
|
|
1233
|
+
"RESET_HISTORY"
|
|
1264
1234
|
],
|
|
1265
1235
|
parameters: []
|
|
1266
1236
|
}
|
|
@@ -1335,17 +1305,38 @@ var clearHistory = {
|
|
|
1335
1305
|
name: spec.name,
|
|
1336
1306
|
similes: spec.similes ? [...spec.similes] : [],
|
|
1337
1307
|
description: spec.description,
|
|
1338
|
-
validate: async (runtime, message,
|
|
1339
|
-
const
|
|
1340
|
-
|
|
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 {
|
|
1341
1338
|
return false;
|
|
1342
1339
|
}
|
|
1343
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1344
|
-
const clearKeywords = ["clear", "reset", "delete", "remove", "clean"];
|
|
1345
|
-
const historyKeywords = ["history", "terminal", "shell", "command"];
|
|
1346
|
-
const hasClearKeyword = clearKeywords.some((keyword) => text.includes(keyword));
|
|
1347
|
-
const hasHistoryKeyword = historyKeywords.some((keyword) => text.includes(keyword));
|
|
1348
|
-
return hasClearKeyword && hasHistoryKeyword;
|
|
1349
1340
|
},
|
|
1350
1341
|
handler: async (runtime, message, _state, _options, callback) => {
|
|
1351
1342
|
const shellService = runtime.getService("shell");
|
|
@@ -1382,389 +1373,12 @@ var clearHistory = {
|
|
|
1382
1373
|
},
|
|
1383
1374
|
examples: spec.examples ?? []
|
|
1384
1375
|
};
|
|
1385
|
-
// actions/executeCommand.ts
|
|
1386
|
-
import {
|
|
1387
|
-
composePromptFromState,
|
|
1388
|
-
logger as logger2,
|
|
1389
|
-
ModelType,
|
|
1390
|
-
parseJSONObjectFromText
|
|
1391
|
-
} from "@elizaos/core";
|
|
1392
|
-
|
|
1393
|
-
// generated/prompts/typescript/prompts.ts
|
|
1394
|
-
var commandExtractionTemplate = `# Extracting shell command from request
|
|
1395
|
-
{{recentMessages}}
|
|
1396
|
-
|
|
1397
|
-
# Instructions: {{senderName}} wants to execute a shell command. Extract the COMPLETE shell command they want to run.
|
|
1398
|
-
|
|
1399
|
-
IMPORTANT:
|
|
1400
|
-
1. Always return the FULL executable shell command, not just the content or partial command.
|
|
1401
|
-
2. If the user mentions installing something, create the appropriate brew/npm/apt command.
|
|
1402
|
-
3. If the user directly provides a command (like "brew install X"), use it exactly as provided.
|
|
1403
|
-
4. ALWAYS extract a command if the user is asking for ANY kind of system operation.
|
|
1404
|
-
|
|
1405
|
-
Common patterns:
|
|
1406
|
-
- "run ls -la" -> command: "ls -la"
|
|
1407
|
-
- "execute npm test" -> command: "npm test"
|
|
1408
|
-
- "show me the files" or "list files" -> command: "ls -la"
|
|
1409
|
-
- "what's in this directory" -> command: "ls -la"
|
|
1410
|
-
- "check git status" -> command: "git status"
|
|
1411
|
-
- "navigate to src folder" -> command: "cd src"
|
|
1412
|
-
- "create a file called test.txt" -> command: "touch test.txt"
|
|
1413
|
-
- "write hello world to a file" -> command: "echo 'hello world' > file.txt"
|
|
1414
|
-
- "create hello.js with javascript code" -> command: "echo 'console.log(\\"Hello, World!\\");' > hello.js"
|
|
1415
|
-
- "create hello_world.py and write a python hello world script inside" -> command: "echo 'print(\\"Hello, World!\\")' > hello_world.py"
|
|
1416
|
-
- "make a new directory" -> command: "mkdir newdir"
|
|
1417
|
-
- "list files inside your filesystem" -> command: "ls -la"
|
|
1418
|
-
- "install orbstack" or "brew install orbstack" -> command: "brew install orbstack"
|
|
1419
|
-
- "install mullvad vpn" -> command: "brew install --cask mullvad-vpn"
|
|
1420
|
-
- "get system info" -> command: "system_profiler SPHardwareDataType"
|
|
1421
|
-
- "check memory usage" -> command: "vm_stat"
|
|
1422
|
-
- "install package" -> command: "brew install <package>"
|
|
1423
|
-
|
|
1424
|
-
Special cases:
|
|
1425
|
-
- "Run it in your shell" or "execute it" -> Extract the command from previous context
|
|
1426
|
-
- "Install these" -> Look for package names in previous messages
|
|
1427
|
-
- Direct commands should be used exactly as provided
|
|
1428
|
-
|
|
1429
|
-
Key rules:
|
|
1430
|
-
1. For file creation with content, use: echo 'content' > filename
|
|
1431
|
-
2. For listing files, use: ls -la (not just ls)
|
|
1432
|
-
3. Always include the echo command when writing to files
|
|
1433
|
-
4. Include all flags and arguments
|
|
1434
|
-
5. When user says "run it", "execute it", or similar, they want you to run the command
|
|
1435
|
-
|
|
1436
|
-
Your response must be formatted as a JSON block:
|
|
1437
|
-
\`\`\`json
|
|
1438
|
-
{
|
|
1439
|
-
"command": "<complete shell command to execute>"
|
|
1440
|
-
}
|
|
1441
|
-
\`\`\``;
|
|
1442
|
-
|
|
1443
|
-
// actions/executeCommand.ts
|
|
1444
|
-
var extractCommand = async (runtime, _message, state) => {
|
|
1445
|
-
const prompt = composePromptFromState({
|
|
1446
|
-
state,
|
|
1447
|
-
template: commandExtractionTemplate
|
|
1448
|
-
});
|
|
1449
|
-
for (let i = 0;i < 3; i++) {
|
|
1450
|
-
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
1451
|
-
prompt
|
|
1452
|
-
});
|
|
1453
|
-
const parsedResponse = parseJSONObjectFromText(response);
|
|
1454
|
-
if (parsedResponse?.command) {
|
|
1455
|
-
return { command: parsedResponse.command };
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
return null;
|
|
1459
|
-
};
|
|
1460
|
-
var spec2 = requireActionSpec("EXECUTE_COMMAND");
|
|
1461
|
-
var executeCommand = {
|
|
1462
|
-
name: spec2.name,
|
|
1463
|
-
similes: spec2.similes ? [...spec2.similes] : [],
|
|
1464
|
-
description: spec2.description,
|
|
1465
|
-
validate: async (runtime, message, _state) => {
|
|
1466
|
-
const shellService = runtime.getService("shell");
|
|
1467
|
-
if (!shellService) {
|
|
1468
|
-
return false;
|
|
1469
|
-
}
|
|
1470
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1471
|
-
const commandKeywords = [
|
|
1472
|
-
"run",
|
|
1473
|
-
"execute",
|
|
1474
|
-
"command",
|
|
1475
|
-
"shell",
|
|
1476
|
-
"install",
|
|
1477
|
-
"brew",
|
|
1478
|
-
"npm",
|
|
1479
|
-
"create",
|
|
1480
|
-
"file",
|
|
1481
|
-
"directory",
|
|
1482
|
-
"folder",
|
|
1483
|
-
"list",
|
|
1484
|
-
"show",
|
|
1485
|
-
"system",
|
|
1486
|
-
"info",
|
|
1487
|
-
"check",
|
|
1488
|
-
"status",
|
|
1489
|
-
"cd",
|
|
1490
|
-
"ls",
|
|
1491
|
-
"mkdir",
|
|
1492
|
-
"echo",
|
|
1493
|
-
"cat",
|
|
1494
|
-
"touch",
|
|
1495
|
-
"git",
|
|
1496
|
-
"build",
|
|
1497
|
-
"test"
|
|
1498
|
-
];
|
|
1499
|
-
const hasCommandKeyword = commandKeywords.some((keyword) => text.includes(keyword));
|
|
1500
|
-
const hasDirectCommand = /^(brew|npm|apt|git|ls|cd|echo|cat|touch|mkdir|rm|mv|cp)\s/i.test(message.content.text || "");
|
|
1501
|
-
return hasCommandKeyword || hasDirectCommand;
|
|
1502
|
-
},
|
|
1503
|
-
handler: async (runtime, message, state, _options, callback) => {
|
|
1504
|
-
const shellService = runtime.getService("shell");
|
|
1505
|
-
if (!shellService) {
|
|
1506
|
-
if (callback) {
|
|
1507
|
-
await callback({
|
|
1508
|
-
text: "Shell service is not available.",
|
|
1509
|
-
source: message.content.source
|
|
1510
|
-
});
|
|
1511
|
-
}
|
|
1512
|
-
return { success: false, error: "Shell service is not available." };
|
|
1513
|
-
}
|
|
1514
|
-
const commandInfo = await extractCommand(runtime, message, state);
|
|
1515
|
-
if (!commandInfo?.command) {
|
|
1516
|
-
logger2.error("Failed to extract command from message:", message.content.text);
|
|
1517
|
-
if (callback) {
|
|
1518
|
-
await callback({
|
|
1519
|
-
text: "Could not determine which command to execute. Please specify a shell command.",
|
|
1520
|
-
source: message.content.source
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1523
|
-
return { success: false, error: "Could not extract command." };
|
|
1524
|
-
}
|
|
1525
|
-
logger2.info(`Extracted command: "${commandInfo.command}"`);
|
|
1526
|
-
try {
|
|
1527
|
-
const conversationId = message.roomId || message.agentId;
|
|
1528
|
-
const result = await shellService.executeCommand(commandInfo.command, conversationId);
|
|
1529
|
-
let responseText = "";
|
|
1530
|
-
if (result.success) {
|
|
1531
|
-
responseText = `Command executed successfully in ${result.executedIn}
|
|
1532
|
-
|
|
1533
|
-
`;
|
|
1534
|
-
if (result.stdout) {
|
|
1535
|
-
responseText += `Output:
|
|
1536
|
-
\`\`\`
|
|
1537
|
-
${result.stdout}
|
|
1538
|
-
\`\`\``;
|
|
1539
|
-
} else {
|
|
1540
|
-
responseText += "Command completed with no output.";
|
|
1541
|
-
}
|
|
1542
|
-
} else {
|
|
1543
|
-
responseText = `Command failed with exit code ${result.exitCode} in ${result.executedIn}
|
|
1544
|
-
|
|
1545
|
-
`;
|
|
1546
|
-
if (result.error) {
|
|
1547
|
-
responseText += `Error: ${result.error}
|
|
1548
|
-
`;
|
|
1549
|
-
}
|
|
1550
|
-
if (result.stderr) {
|
|
1551
|
-
responseText += `
|
|
1552
|
-
Error output:
|
|
1553
|
-
\`\`\`
|
|
1554
|
-
${result.stderr}
|
|
1555
|
-
\`\`\``;
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
const response = {
|
|
1559
|
-
text: responseText,
|
|
1560
|
-
source: message.content.source
|
|
1561
|
-
};
|
|
1562
|
-
if (callback) {
|
|
1563
|
-
await callback(response);
|
|
1564
|
-
}
|
|
1565
|
-
return { success: result.success, text: responseText };
|
|
1566
|
-
} catch (error) {
|
|
1567
|
-
logger2.error("Error executing command:", error);
|
|
1568
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1569
|
-
if (callback) {
|
|
1570
|
-
await callback({
|
|
1571
|
-
text: `Failed to execute command: ${errorMessage}`,
|
|
1572
|
-
source: message.content.source
|
|
1573
|
-
});
|
|
1574
|
-
}
|
|
1575
|
-
return { success: false, error: errorMessage };
|
|
1576
|
-
}
|
|
1577
|
-
},
|
|
1578
|
-
examples: spec2.examples ?? []
|
|
1579
|
-
};
|
|
1580
|
-
// actions/processAction.ts
|
|
1581
|
-
import { composePromptFromState as composePromptFromState2, logger as logger3, ModelType as ModelType2 } from "@elizaos/core";
|
|
1582
|
-
var processActionTemplate = `You are helping extract process management parameters from user messages.
|
|
1583
|
-
|
|
1584
|
-
Recent conversation:
|
|
1585
|
-
{{recentMessages}}
|
|
1586
|
-
|
|
1587
|
-
Based on the conversation, extract the process action parameters:
|
|
1588
|
-
- action: The action to perform (list, poll, log, write, send-keys, submit, paste, kill, clear, remove)
|
|
1589
|
-
- sessionId: The session ID (required for all actions except "list")
|
|
1590
|
-
- data: Data to write (for "write" action)
|
|
1591
|
-
- keys: Array of key tokens (for "send-keys" action)
|
|
1592
|
-
- literal: Literal string to send (for "send-keys" action)
|
|
1593
|
-
- text: Text to paste (for "paste" action)
|
|
1594
|
-
- eof: Whether to close stdin after write (for "write" action)
|
|
1595
|
-
- offset: Log offset (for "log" action)
|
|
1596
|
-
- limit: Log limit (for "log" action)
|
|
1597
|
-
|
|
1598
|
-
Respond with a JSON object containing the extracted parameters:
|
|
1599
|
-
\`\`\`json
|
|
1600
|
-
{
|
|
1601
|
-
"action": "list|poll|log|write|send-keys|submit|paste|kill|clear|remove",
|
|
1602
|
-
"sessionId": "optional-session-id",
|
|
1603
|
-
"data": "optional-data",
|
|
1604
|
-
"keys": ["optional", "key", "tokens"],
|
|
1605
|
-
"literal": "optional-literal",
|
|
1606
|
-
"text": "optional-paste-text",
|
|
1607
|
-
"eof": false,
|
|
1608
|
-
"offset": 0,
|
|
1609
|
-
"limit": 100
|
|
1610
|
-
}
|
|
1611
|
-
\`\`\``;
|
|
1612
|
-
function extractJsonFromResponse(response) {
|
|
1613
|
-
const jsonMatch = response.match(/```json\s*([\s\S]*?)\s*```/);
|
|
1614
|
-
if (jsonMatch?.[1]) {
|
|
1615
|
-
try {
|
|
1616
|
-
return JSON.parse(jsonMatch[1]);
|
|
1617
|
-
} catch {}
|
|
1618
|
-
}
|
|
1619
|
-
try {
|
|
1620
|
-
const trimmed = response.trim();
|
|
1621
|
-
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
1622
|
-
return JSON.parse(trimmed);
|
|
1623
|
-
}
|
|
1624
|
-
} catch {}
|
|
1625
|
-
return null;
|
|
1626
|
-
}
|
|
1627
|
-
var processAction = {
|
|
1628
|
-
name: "MANAGE_PROCESS",
|
|
1629
|
-
similes: [
|
|
1630
|
-
"PROCESS_LIST",
|
|
1631
|
-
"PROCESS_POLL",
|
|
1632
|
-
"PROCESS_LOG",
|
|
1633
|
-
"PROCESS_WRITE",
|
|
1634
|
-
"PROCESS_KILL",
|
|
1635
|
-
"LIST_SESSIONS",
|
|
1636
|
-
"POLL_SESSION",
|
|
1637
|
-
"KILL_SESSION",
|
|
1638
|
-
"CHECK_PROCESS",
|
|
1639
|
-
"SEND_KEYS"
|
|
1640
|
-
],
|
|
1641
|
-
description: "Manage running shell/exec sessions: list, poll, log, write, send-keys, submit, paste, kill, clear, remove",
|
|
1642
|
-
validate: async (_runtime, message) => {
|
|
1643
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1644
|
-
const processKeywords = [
|
|
1645
|
-
"process",
|
|
1646
|
-
"session",
|
|
1647
|
-
"sessions",
|
|
1648
|
-
"list",
|
|
1649
|
-
"poll",
|
|
1650
|
-
"log",
|
|
1651
|
-
"write",
|
|
1652
|
-
"send-keys",
|
|
1653
|
-
"send keys",
|
|
1654
|
-
"submit",
|
|
1655
|
-
"paste",
|
|
1656
|
-
"kill",
|
|
1657
|
-
"clear",
|
|
1658
|
-
"remove",
|
|
1659
|
-
"running",
|
|
1660
|
-
"background"
|
|
1661
|
-
];
|
|
1662
|
-
const actionKeywords = [
|
|
1663
|
-
"check",
|
|
1664
|
-
"show",
|
|
1665
|
-
"get",
|
|
1666
|
-
"view",
|
|
1667
|
-
"manage",
|
|
1668
|
-
"stop",
|
|
1669
|
-
"terminate",
|
|
1670
|
-
"status"
|
|
1671
|
-
];
|
|
1672
|
-
const hasProcessKeyword = processKeywords.some((kw) => text.includes(kw));
|
|
1673
|
-
const hasActionKeyword = actionKeywords.some((kw) => text.includes(kw));
|
|
1674
|
-
return hasProcessKeyword || hasActionKeyword && text.includes("session");
|
|
1675
|
-
},
|
|
1676
|
-
handler: async (runtime, message, state) => {
|
|
1677
|
-
const shellService = runtime.getService("shell");
|
|
1678
|
-
if (!shellService) {
|
|
1679
|
-
return {
|
|
1680
|
-
success: false,
|
|
1681
|
-
text: "Shell service is not available.",
|
|
1682
|
-
error: "Shell service not found"
|
|
1683
|
-
};
|
|
1684
|
-
}
|
|
1685
|
-
const composedState = state ?? await runtime.composeState(message);
|
|
1686
|
-
const prompt = composePromptFromState2({
|
|
1687
|
-
state: composedState,
|
|
1688
|
-
template: processActionTemplate
|
|
1689
|
-
});
|
|
1690
|
-
let params = null;
|
|
1691
|
-
const text = message.content.text?.toLowerCase() || "";
|
|
1692
|
-
if (text.includes("list") && (text.includes("session") || text.includes("process"))) {
|
|
1693
|
-
params = { action: "list" };
|
|
1694
|
-
} else {
|
|
1695
|
-
try {
|
|
1696
|
-
const response = await runtime.useModel(ModelType2.TEXT_SMALL, {
|
|
1697
|
-
prompt
|
|
1698
|
-
});
|
|
1699
|
-
params = extractJsonFromResponse(String(response));
|
|
1700
|
-
} catch (error) {
|
|
1701
|
-
logger3.error("Failed to extract process parameters:", error);
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
if (!params) {
|
|
1705
|
-
params = { action: "list" };
|
|
1706
|
-
}
|
|
1707
|
-
const result = await shellService.processAction(params);
|
|
1708
|
-
return {
|
|
1709
|
-
success: result.success,
|
|
1710
|
-
text: result.message
|
|
1711
|
-
};
|
|
1712
|
-
},
|
|
1713
|
-
examples: [
|
|
1714
|
-
[
|
|
1715
|
-
{
|
|
1716
|
-
name: "{{user1}}",
|
|
1717
|
-
content: { text: "List all running processes" }
|
|
1718
|
-
},
|
|
1719
|
-
{
|
|
1720
|
-
name: "{{agentName}}",
|
|
1721
|
-
content: {
|
|
1722
|
-
text: `Here are the running sessions:
|
|
1723
|
-
calm-harbor running 5m30s :: npm install
|
|
1724
|
-
brisk-reef completed 2m15s :: git status`,
|
|
1725
|
-
action: "MANAGE_PROCESS"
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
],
|
|
1729
|
-
[
|
|
1730
|
-
{
|
|
1731
|
-
name: "{{user1}}",
|
|
1732
|
-
content: { text: "Check the status of session calm-harbor" }
|
|
1733
|
-
},
|
|
1734
|
-
{
|
|
1735
|
-
name: "{{agentName}}",
|
|
1736
|
-
content: {
|
|
1737
|
-
text: `Session calm-harbor is still running.
|
|
1738
|
-
|
|
1739
|
-
Output:
|
|
1740
|
-
npm WARN deprecated...
|
|
1741
|
-
|
|
1742
|
-
Process still running.`,
|
|
1743
|
-
action: "MANAGE_PROCESS"
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
],
|
|
1747
|
-
[
|
|
1748
|
-
{
|
|
1749
|
-
name: "{{user1}}",
|
|
1750
|
-
content: { text: "Kill the session brisk-reef" }
|
|
1751
|
-
},
|
|
1752
|
-
{
|
|
1753
|
-
name: "{{agentName}}",
|
|
1754
|
-
content: {
|
|
1755
|
-
text: "Killed session brisk-reef.",
|
|
1756
|
-
action: "MANAGE_PROCESS"
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1759
|
-
]
|
|
1760
|
-
]
|
|
1761
|
-
};
|
|
1762
1376
|
// approvals/allowlist.ts
|
|
1763
1377
|
import crypto2 from "node:crypto";
|
|
1764
1378
|
import fs from "node:fs";
|
|
1765
1379
|
import os from "node:os";
|
|
1766
1380
|
import path from "node:path";
|
|
1767
|
-
import { logger as
|
|
1381
|
+
import { logger as logger2 } from "@elizaos/core";
|
|
1768
1382
|
|
|
1769
1383
|
// approvals/types.ts
|
|
1770
1384
|
var DEFAULT_SAFE_BINS = [
|
|
@@ -1902,12 +1516,12 @@ function readApprovalsSnapshot() {
|
|
|
1902
1516
|
try {
|
|
1903
1517
|
parsed = JSON.parse(raw);
|
|
1904
1518
|
} catch (parseError) {
|
|
1905
|
-
|
|
1519
|
+
logger2.warn({ src: "exec-approval", parseError, filePath }, "Failed to parse approval config snapshot - file may be corrupted");
|
|
1906
1520
|
parsed = null;
|
|
1907
1521
|
}
|
|
1908
1522
|
const file = parsed?.version === 1 ? normalizeApprovals(parsed) : normalizeApprovals({ version: 1, agents: {} });
|
|
1909
1523
|
if (parsed && parsed.version !== 1) {
|
|
1910
|
-
|
|
1524
|
+
logger2.warn({ src: "exec-approval", version: parsed.version, filePath }, "Approval config snapshot has unexpected version");
|
|
1911
1525
|
}
|
|
1912
1526
|
return {
|
|
1913
1527
|
path: filePath,
|
|
@@ -1921,7 +1535,7 @@ function loadApprovals() {
|
|
|
1921
1535
|
const filePath = getApprovalFilePath();
|
|
1922
1536
|
try {
|
|
1923
1537
|
if (!fs.existsSync(filePath)) {
|
|
1924
|
-
|
|
1538
|
+
logger2.debug({ src: "exec-approval", filePath }, "Approval config file does not exist, using defaults");
|
|
1925
1539
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1926
1540
|
}
|
|
1927
1541
|
const raw = fs.readFileSync(filePath, "utf8");
|
|
@@ -1929,16 +1543,16 @@ function loadApprovals() {
|
|
|
1929
1543
|
try {
|
|
1930
1544
|
parsed = JSON.parse(raw);
|
|
1931
1545
|
} catch (parseError) {
|
|
1932
|
-
|
|
1546
|
+
logger2.error({ src: "exec-approval", parseError, filePath }, "Failed to parse approval config JSON - file may be corrupted. Using defaults.");
|
|
1933
1547
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1934
1548
|
}
|
|
1935
1549
|
if (parsed?.version !== 1) {
|
|
1936
|
-
|
|
1550
|
+
logger2.warn({ src: "exec-approval", version: parsed?.version, filePath }, "Approval config has unexpected version, using defaults");
|
|
1937
1551
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1938
1552
|
}
|
|
1939
1553
|
return normalizeApprovals(parsed);
|
|
1940
1554
|
} catch (error) {
|
|
1941
|
-
|
|
1555
|
+
logger2.error({ src: "exec-approval", error, filePath }, "Failed to load approval config - using defaults. This may indicate a permissions issue.");
|
|
1942
1556
|
return normalizeApprovals({ version: 1, agents: {} });
|
|
1943
1557
|
}
|
|
1944
1558
|
}
|
|
@@ -1954,7 +1568,7 @@ function saveApprovals(file) {
|
|
|
1954
1568
|
fs.chmodSync(filePath, 384);
|
|
1955
1569
|
} catch {}
|
|
1956
1570
|
} catch (error) {
|
|
1957
|
-
|
|
1571
|
+
logger2.error({ src: "exec-approval", error, filePath }, "Failed to save approval configuration");
|
|
1958
1572
|
throw new Error(`Failed to save approval configuration to ${filePath}: ${error}`);
|
|
1959
1573
|
}
|
|
1960
1574
|
}
|
|
@@ -1973,7 +1587,7 @@ function ensureApprovals() {
|
|
|
1973
1587
|
try {
|
|
1974
1588
|
saveApprovals(updated);
|
|
1975
1589
|
} catch (error) {
|
|
1976
|
-
|
|
1590
|
+
logger2.warn({ src: "exec-approval", error }, "Failed to save approval config during ensureApprovals - " + "returning in-memory config. Changes will not persist.");
|
|
1977
1591
|
throw error;
|
|
1978
1592
|
}
|
|
1979
1593
|
return updated;
|
|
@@ -1995,7 +1609,7 @@ function resolveApprovals(agentId, overrides) {
|
|
|
1995
1609
|
try {
|
|
1996
1610
|
file = ensureApprovals();
|
|
1997
1611
|
} catch (error) {
|
|
1998
|
-
|
|
1612
|
+
logger2.warn({ src: "exec-approval", error }, "Could not ensure approval config exists - using read-only config");
|
|
1999
1613
|
file = loadApprovals();
|
|
2000
1614
|
}
|
|
2001
1615
|
return resolveApprovalsFromFile({
|
|
@@ -2137,7 +1751,7 @@ function recordAllowlistUse(approvals, agentId, entry, command, resolvedPath) {
|
|
|
2137
1751
|
saveApprovals(approvals);
|
|
2138
1752
|
return true;
|
|
2139
1753
|
} catch (error) {
|
|
2140
|
-
|
|
1754
|
+
logger2.warn({ src: "exec-approval", error, pattern: entry.pattern }, "Failed to record allowlist usage - continuing without update");
|
|
2141
1755
|
return false;
|
|
2142
1756
|
}
|
|
2143
1757
|
}
|
|
@@ -2148,11 +1762,11 @@ function addAllowlistEntry(approvals, agentId, pattern) {
|
|
|
2148
1762
|
const allowlist = Array.isArray(existing.allowlist) ? existing.allowlist : [];
|
|
2149
1763
|
const trimmed = pattern.trim();
|
|
2150
1764
|
if (!trimmed) {
|
|
2151
|
-
|
|
1765
|
+
logger2.warn({ src: "exec-approval" }, "Attempted to add empty pattern to allowlist");
|
|
2152
1766
|
return false;
|
|
2153
1767
|
}
|
|
2154
1768
|
if (allowlist.some((entry) => entry.pattern === trimmed)) {
|
|
2155
|
-
|
|
1769
|
+
logger2.debug({ src: "exec-approval", pattern: trimmed }, "Pattern already in allowlist");
|
|
2156
1770
|
return false;
|
|
2157
1771
|
}
|
|
2158
1772
|
allowlist.push({
|
|
@@ -2164,15 +1778,19 @@ function addAllowlistEntry(approvals, agentId, pattern) {
|
|
|
2164
1778
|
approvals.agents = agents;
|
|
2165
1779
|
try {
|
|
2166
1780
|
saveApprovals(approvals);
|
|
2167
|
-
|
|
1781
|
+
logger2.info({ src: "exec-approval", pattern: trimmed, agentId: target }, "Added pattern to allowlist");
|
|
2168
1782
|
return true;
|
|
2169
1783
|
} catch (error) {
|
|
2170
|
-
|
|
1784
|
+
logger2.error({ src: "exec-approval", error, pattern: trimmed }, "Failed to save allowlist after adding entry");
|
|
2171
1785
|
return false;
|
|
2172
1786
|
}
|
|
2173
1787
|
}
|
|
2174
1788
|
function minSecurity(a, b) {
|
|
2175
|
-
const order = {
|
|
1789
|
+
const order = {
|
|
1790
|
+
deny: 0,
|
|
1791
|
+
allowlist: 1,
|
|
1792
|
+
full: 2
|
|
1793
|
+
};
|
|
2176
1794
|
return order[a] <= order[b] ? a : b;
|
|
2177
1795
|
}
|
|
2178
1796
|
function maxAsk(a, b) {
|
|
@@ -2182,8 +1800,16 @@ function maxAsk(a, b) {
|
|
|
2182
1800
|
// approvals/analysis.ts
|
|
2183
1801
|
import fs2 from "node:fs";
|
|
2184
1802
|
import path2 from "node:path";
|
|
2185
|
-
var DISALLOWED_PIPELINE_TOKENS = new Set([
|
|
2186
|
-
|
|
1803
|
+
var DISALLOWED_PIPELINE_TOKENS = new Set([
|
|
1804
|
+
">",
|
|
1805
|
+
"<",
|
|
1806
|
+
"`",
|
|
1807
|
+
`
|
|
1808
|
+
`,
|
|
1809
|
+
"\r",
|
|
1810
|
+
"(",
|
|
1811
|
+
")"
|
|
1812
|
+
]);
|
|
2187
1813
|
var DOUBLE_QUOTE_ESCAPES = new Set(["\\", '"', "$", "`", `
|
|
2188
1814
|
`, "\r"]);
|
|
2189
1815
|
var WINDOWS_UNSUPPORTED_TOKENS = new Set([
|
|
@@ -2494,7 +2120,11 @@ function analyzeShellCommand(params) {
|
|
|
2494
2120
|
}
|
|
2495
2121
|
const segments2 = parseSegmentsFromParts(pipelineSplit.segments, params.cwd, params.env);
|
|
2496
2122
|
if (!segments2) {
|
|
2497
|
-
return {
|
|
2123
|
+
return {
|
|
2124
|
+
ok: false,
|
|
2125
|
+
reason: "unable to parse shell segment",
|
|
2126
|
+
segments: []
|
|
2127
|
+
};
|
|
2498
2128
|
}
|
|
2499
2129
|
chains.push(segments2);
|
|
2500
2130
|
allSegments.push(...segments2);
|
|
@@ -2525,7 +2155,11 @@ function analyzeWindowsCommand(params) {
|
|
|
2525
2155
|
}
|
|
2526
2156
|
const argv = tokenizeWindowsSegment(params.command);
|
|
2527
2157
|
if (!argv || argv.length === 0) {
|
|
2528
|
-
return {
|
|
2158
|
+
return {
|
|
2159
|
+
ok: false,
|
|
2160
|
+
reason: "unable to parse windows command",
|
|
2161
|
+
segments: []
|
|
2162
|
+
};
|
|
2529
2163
|
}
|
|
2530
2164
|
return {
|
|
2531
2165
|
ok: true,
|
|
@@ -2780,7 +2414,10 @@ function evaluateExecAllowlist(params) {
|
|
|
2780
2414
|
skillBins: params.skillBins,
|
|
2781
2415
|
autoAllowSkills: params.autoAllowSkills
|
|
2782
2416
|
});
|
|
2783
|
-
return {
|
|
2417
|
+
return {
|
|
2418
|
+
allowlistSatisfied: result.satisfied,
|
|
2419
|
+
allowlistMatches: result.matches
|
|
2420
|
+
};
|
|
2784
2421
|
}
|
|
2785
2422
|
function evaluateShellAllowlist(params) {
|
|
2786
2423
|
const chainParts = isWindowsPlatform(params.platform) ? null : splitCommandChain(params.command);
|
|
@@ -2861,7 +2498,7 @@ function requiresExecApproval(params) {
|
|
|
2861
2498
|
return params.ask === "always" || params.ask === "on-miss" && params.security === "allowlist" && (!params.analysisOk || !params.allowlistSatisfied);
|
|
2862
2499
|
}
|
|
2863
2500
|
// approvals/service.ts
|
|
2864
|
-
import { logger as
|
|
2501
|
+
import { logger as logger3, Service } from "@elizaos/core";
|
|
2865
2502
|
var EXEC_APPROVAL_OPTIONS = [
|
|
2866
2503
|
{ name: "allow-once", description: "Allow this one time" },
|
|
2867
2504
|
{ name: "allow-always", description: "Always allow this" },
|
|
@@ -2884,7 +2521,7 @@ class ExecApprovalService extends Service {
|
|
|
2884
2521
|
try {
|
|
2885
2522
|
service.approvalConfig = resolveApprovals(runtime.agentId);
|
|
2886
2523
|
} catch (error) {
|
|
2887
|
-
|
|
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");
|
|
2888
2525
|
service.approvalConfig = {
|
|
2889
2526
|
path: "",
|
|
2890
2527
|
socketPath: "",
|
|
@@ -2905,11 +2542,11 @@ class ExecApprovalService extends Service {
|
|
|
2905
2542
|
file: { version: 1, agents: {} }
|
|
2906
2543
|
};
|
|
2907
2544
|
}
|
|
2908
|
-
|
|
2545
|
+
logger3.info({ src: "service:exec_approval", agentId: runtime.agentId }, "ExecApprovalService started");
|
|
2909
2546
|
return service;
|
|
2910
2547
|
}
|
|
2911
2548
|
async stop() {
|
|
2912
|
-
|
|
2549
|
+
logger3.debug({ src: "service:exec_approval" }, "ExecApprovalService stopped");
|
|
2913
2550
|
}
|
|
2914
2551
|
loadConfig(agentId) {
|
|
2915
2552
|
this.approvalConfig = resolveApprovals(agentId ?? this.runtime?.agentId);
|
|
@@ -2981,7 +2618,7 @@ class ExecApprovalService extends Service {
|
|
|
2981
2618
|
}
|
|
2982
2619
|
}
|
|
2983
2620
|
if (recordingFailed) {
|
|
2984
|
-
|
|
2621
|
+
logger3.debug({ src: "service:exec_approval", command: params.command }, "Some allowlist usage records failed to save - command will still proceed");
|
|
2985
2622
|
}
|
|
2986
2623
|
return {
|
|
2987
2624
|
allowed: true,
|
|
@@ -3037,13 +2674,17 @@ class ExecApprovalService extends Service {
|
|
|
3037
2674
|
async requestApproval(request) {
|
|
3038
2675
|
const approvalService = this.runtime?.getService("approval");
|
|
3039
2676
|
if (!approvalService) {
|
|
3040
|
-
|
|
2677
|
+
logger3.warn({ src: "service:exec_approval" }, "ApprovalService not available, denying by default");
|
|
3041
2678
|
return {
|
|
3042
2679
|
decision: "deny",
|
|
3043
2680
|
timedOut: false
|
|
3044
2681
|
};
|
|
3045
2682
|
}
|
|
3046
|
-
const descriptionLines = [
|
|
2683
|
+
const descriptionLines = [
|
|
2684
|
+
"**Exec Approval Required**",
|
|
2685
|
+
"",
|
|
2686
|
+
`Command: \`${request.command}\``
|
|
2687
|
+
];
|
|
3047
2688
|
if (request.cwd) {
|
|
3048
2689
|
descriptionLines.push(`CWD: \`${request.cwd}\``);
|
|
3049
2690
|
}
|
|
@@ -3085,13 +2726,17 @@ class ExecApprovalService extends Service {
|
|
|
3085
2726
|
async requestApprovalAsync(request, callbacks) {
|
|
3086
2727
|
const approvalService = this.runtime?.getService("approval");
|
|
3087
2728
|
if (!approvalService) {
|
|
3088
|
-
|
|
2729
|
+
logger3.warn({ src: "service:exec_approval" }, "ApprovalService not available");
|
|
3089
2730
|
if (callbacks?.onDenied) {
|
|
3090
2731
|
await callbacks.onDenied();
|
|
3091
2732
|
}
|
|
3092
2733
|
throw new Error("ApprovalService not available");
|
|
3093
2734
|
}
|
|
3094
|
-
const descriptionLines = [
|
|
2735
|
+
const descriptionLines = [
|
|
2736
|
+
"**Exec Approval Required**",
|
|
2737
|
+
"",
|
|
2738
|
+
`Command: \`${request.command}\``
|
|
2739
|
+
];
|
|
3095
2740
|
if (request.cwd) {
|
|
3096
2741
|
descriptionLines.push(`CWD: \`${request.cwd}\``);
|
|
3097
2742
|
}
|
|
@@ -3156,7 +2801,7 @@ class ExecApprovalService extends Service {
|
|
|
3156
2801
|
}
|
|
3157
2802
|
async getPendingApprovals(roomId) {
|
|
3158
2803
|
if (!this.runtime) {
|
|
3159
|
-
|
|
2804
|
+
logger3.warn({ src: "service:exec_approval" }, "Cannot get pending approvals - runtime not available");
|
|
3160
2805
|
return [];
|
|
3161
2806
|
}
|
|
3162
2807
|
try {
|
|
@@ -3180,7 +2825,7 @@ class ExecApprovalService extends Service {
|
|
|
3180
2825
|
};
|
|
3181
2826
|
});
|
|
3182
2827
|
} catch (error) {
|
|
3183
|
-
|
|
2828
|
+
logger3.error({ src: "service:exec_approval", error, roomId }, "Failed to get pending approvals");
|
|
3184
2829
|
return [];
|
|
3185
2830
|
}
|
|
3186
2831
|
}
|
|
@@ -3198,19 +2843,20 @@ function mapOptionToDecision(option) {
|
|
|
3198
2843
|
// providers/shellHistoryProvider.ts
|
|
3199
2844
|
import {
|
|
3200
2845
|
addHeader,
|
|
3201
|
-
logger as
|
|
2846
|
+
logger as logger4
|
|
3202
2847
|
} from "@elizaos/core";
|
|
3203
2848
|
var MAX_OUTPUT_LENGTH = 8000;
|
|
3204
2849
|
var TRUNCATE_SEGMENT_LENGTH = 4000;
|
|
3205
|
-
var
|
|
2850
|
+
var spec2 = requireProviderSpec("SHELL_HISTORY");
|
|
3206
2851
|
var shellHistoryProvider = {
|
|
3207
|
-
name:
|
|
2852
|
+
name: spec2.name,
|
|
3208
2853
|
description: "Provides recent shell command history, current working directory, and file operations within the restricted environment",
|
|
3209
2854
|
position: 99,
|
|
2855
|
+
dynamic: true,
|
|
3210
2856
|
get: async (runtime, message, _state) => {
|
|
3211
2857
|
const shellService = runtime.getService("shell");
|
|
3212
2858
|
if (!shellService) {
|
|
3213
|
-
|
|
2859
|
+
logger4.warn("[shellHistoryProvider] Shell service not found");
|
|
3214
2860
|
return {
|
|
3215
2861
|
values: {
|
|
3216
2862
|
shellHistory: "Shell service is not available",
|
|
@@ -3310,15 +2956,62 @@ ${addHeader("# Shell History (Last 10)", historyText)}${fileOpsText}`;
|
|
|
3310
2956
|
};
|
|
3311
2957
|
}
|
|
3312
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
|
+
|
|
3313
3006
|
// services/shellService.ts
|
|
3314
3007
|
import path6 from "node:path";
|
|
3315
|
-
import { logger as
|
|
3008
|
+
import { logger as logger7, Service as Service2 } from "@elizaos/core";
|
|
3316
3009
|
import spawn2 from "cross-spawn";
|
|
3317
3010
|
|
|
3318
3011
|
// utils/config.ts
|
|
3319
3012
|
import fs3 from "node:fs";
|
|
3320
3013
|
import path3 from "node:path";
|
|
3321
|
-
import { logger as
|
|
3014
|
+
import { logger as logger5 } from "@elizaos/core";
|
|
3322
3015
|
import { z } from "zod";
|
|
3323
3016
|
var configSchema = z.object({
|
|
3324
3017
|
enabled: z.boolean(),
|
|
@@ -3365,7 +3058,9 @@ function loadShellConfig() {
|
|
|
3365
3058
|
const defaultBackgroundMs = parseInt(process.env.SHELL_BACKGROUND_MS || "10000", 10);
|
|
3366
3059
|
const allowBackground = process.env.SHELL_ALLOW_BACKGROUND !== "false";
|
|
3367
3060
|
const customForbidden = process.env.SHELL_FORBIDDEN_COMMANDS ? process.env.SHELL_FORBIDDEN_COMMANDS.split(",").map((cmd) => cmd.trim()) : [];
|
|
3368
|
-
const forbiddenCommands = [
|
|
3061
|
+
const forbiddenCommands = [
|
|
3062
|
+
...new Set([...DEFAULT_FORBIDDEN_COMMANDS, ...customForbidden])
|
|
3063
|
+
];
|
|
3369
3064
|
const config = {
|
|
3370
3065
|
enabled: true,
|
|
3371
3066
|
allowedDirectory,
|
|
@@ -3387,7 +3082,7 @@ function loadShellConfig() {
|
|
|
3387
3082
|
throw new Error(`SHELL_ALLOWED_DIRECTORY is not a directory: ${allowedDirectory}`);
|
|
3388
3083
|
}
|
|
3389
3084
|
config.allowedDirectory = path3.resolve(allowedDirectory);
|
|
3390
|
-
|
|
3085
|
+
logger5.info(`Shell plugin enabled with allowed directory: ${config.allowedDirectory}, ` + `background: ${allowBackground}, timeout: ${timeout}ms`);
|
|
3391
3086
|
} catch (error) {
|
|
3392
3087
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
3393
3088
|
throw new Error(`SHELL_ALLOWED_DIRECTORY does not exist: ${allowedDirectory}`);
|
|
@@ -3398,35 +3093,42 @@ function loadShellConfig() {
|
|
|
3398
3093
|
}
|
|
3399
3094
|
// utils/pathUtils.ts
|
|
3400
3095
|
import path4 from "node:path";
|
|
3401
|
-
import { logger as
|
|
3096
|
+
import { logger as logger6 } from "@elizaos/core";
|
|
3402
3097
|
function validatePath(commandPath, allowedDir, currentDir) {
|
|
3403
3098
|
const resolvedPath = path4.resolve(currentDir, commandPath);
|
|
3404
3099
|
const normalizedPath = path4.normalize(resolvedPath);
|
|
3405
3100
|
const normalizedAllowed = path4.normalize(allowedDir);
|
|
3406
3101
|
if (!normalizedPath.startsWith(normalizedAllowed)) {
|
|
3407
|
-
|
|
3102
|
+
logger6.warn(`Path validation failed: ${normalizedPath} is outside allowed directory ${normalizedAllowed}`);
|
|
3408
3103
|
return null;
|
|
3409
3104
|
}
|
|
3410
3105
|
return normalizedPath;
|
|
3411
3106
|
}
|
|
3412
3107
|
function isSafeCommand(command) {
|
|
3413
3108
|
const pathTraversalPatterns = [/\.\.\//g, /\.\.\\/g, /\/\.\./g, /\\\.\./g];
|
|
3414
|
-
const dangerousPatterns = [
|
|
3109
|
+
const dangerousPatterns = [
|
|
3110
|
+
/\$\(/g,
|
|
3111
|
+
/`[^']*`/g,
|
|
3112
|
+
/\|\s*sudo/g,
|
|
3113
|
+
/;\s*sudo/g,
|
|
3114
|
+
/&\s*&/g,
|
|
3115
|
+
/\|\s*\|/g
|
|
3116
|
+
];
|
|
3415
3117
|
for (const pattern of pathTraversalPatterns) {
|
|
3416
3118
|
if (pattern.test(command)) {
|
|
3417
|
-
|
|
3119
|
+
logger6.warn(`Path traversal detected in command: ${command}`);
|
|
3418
3120
|
return false;
|
|
3419
3121
|
}
|
|
3420
3122
|
}
|
|
3421
3123
|
for (const pattern of dangerousPatterns) {
|
|
3422
3124
|
if (pattern.test(command)) {
|
|
3423
|
-
|
|
3125
|
+
logger6.warn(`Dangerous pattern detected in command: ${command}`);
|
|
3424
3126
|
return false;
|
|
3425
3127
|
}
|
|
3426
3128
|
}
|
|
3427
3129
|
const pipeCount = (command.match(/\|/g) || []).length;
|
|
3428
3130
|
if (pipeCount > 1) {
|
|
3429
|
-
|
|
3131
|
+
logger6.warn(`Multiple pipes detected in command: ${command}`);
|
|
3430
3132
|
return false;
|
|
3431
3133
|
}
|
|
3432
3134
|
return true;
|
|
@@ -4159,7 +3861,10 @@ function randomChoice(values, fallback) {
|
|
|
4159
3861
|
return values[Math.floor(Math.random() * values.length)] ?? fallback;
|
|
4160
3862
|
}
|
|
4161
3863
|
function createSlugBase(words = 2) {
|
|
4162
|
-
const parts = [
|
|
3864
|
+
const parts = [
|
|
3865
|
+
randomChoice(SLUG_ADJECTIVES, "steady"),
|
|
3866
|
+
randomChoice(SLUG_NOUNS, "harbor")
|
|
3867
|
+
];
|
|
4163
3868
|
if (words > 2) {
|
|
4164
3869
|
parts.push(randomChoice(SLUG_NOUNS, "reef"));
|
|
4165
3870
|
}
|
|
@@ -4379,7 +4084,7 @@ class ShellService extends Service2 {
|
|
|
4379
4084
|
}
|
|
4380
4085
|
static async start(runtime) {
|
|
4381
4086
|
const instance = new ShellService(runtime);
|
|
4382
|
-
|
|
4087
|
+
logger7.info("Shell service initialized with PTY, background execution, and history tracking");
|
|
4383
4088
|
return instance;
|
|
4384
4089
|
}
|
|
4385
4090
|
async stop() {
|
|
@@ -4387,13 +4092,13 @@ class ShellService extends Service2 {
|
|
|
4387
4092
|
for (const session of runningSessions2) {
|
|
4388
4093
|
try {
|
|
4389
4094
|
killSession(session);
|
|
4390
|
-
|
|
4095
|
+
logger7.debug(`Killed shell session: ${session.id}`);
|
|
4391
4096
|
} catch (err) {
|
|
4392
|
-
|
|
4097
|
+
logger7.warn(`Failed to kill shell session ${session.id}: ${err}`);
|
|
4393
4098
|
}
|
|
4394
4099
|
}
|
|
4395
4100
|
this.commandHistory.clear();
|
|
4396
|
-
|
|
4101
|
+
logger7.info(`Shell service stopped, cleaned up ${runningSessions2.length} running sessions`);
|
|
4397
4102
|
}
|
|
4398
4103
|
get capabilityDescription() {
|
|
4399
4104
|
return "Execute shell commands with PTY support, background execution, and session management";
|
|
@@ -4415,7 +4120,7 @@ class ShellService extends Service2 {
|
|
|
4415
4120
|
if (this.runtime && this.runtime.sandboxMode) {
|
|
4416
4121
|
const hostApiUrl = this.runtime.getSetting("SANDBOX_HOST_API_URL") ?? "http://localhost:2138";
|
|
4417
4122
|
const runtimeFetch = this.runtime.fetch ?? globalThis.fetch;
|
|
4418
|
-
|
|
4123
|
+
logger7.info(`[shell:sandbox] routing exec to ${hostApiUrl}: ${command.substring(0, 100)}`);
|
|
4419
4124
|
try {
|
|
4420
4125
|
const response = await runtimeFetch(`${hostApiUrl}/api/sandbox/exec`, {
|
|
4421
4126
|
method: "POST",
|
|
@@ -4427,7 +4132,7 @@ class ShellService extends Service2 {
|
|
|
4427
4132
|
})
|
|
4428
4133
|
});
|
|
4429
4134
|
const result2 = await response.json();
|
|
4430
|
-
|
|
4135
|
+
logger7.info(`[shell:sandbox] exec completed: exit=${result2.exitCode} duration=${result2.durationMs}ms`);
|
|
4431
4136
|
return {
|
|
4432
4137
|
success: result2.exitCode === 0,
|
|
4433
4138
|
stdout: result2.stdout,
|
|
@@ -4437,7 +4142,7 @@ class ShellService extends Service2 {
|
|
|
4437
4142
|
};
|
|
4438
4143
|
} catch (err) {
|
|
4439
4144
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
4440
|
-
|
|
4145
|
+
logger7.error(`[shell:sandbox] exec failed: ${errMsg}`);
|
|
4441
4146
|
return {
|
|
4442
4147
|
success: false,
|
|
4443
4148
|
stdout: "",
|
|
@@ -5049,7 +4754,7 @@ Warnings:
|
|
|
5049
4754
|
}
|
|
5050
4755
|
clearCommandHistory(conversationId) {
|
|
5051
4756
|
this.commandHistory.delete(conversationId);
|
|
5052
|
-
|
|
4757
|
+
logger7.info(`Cleared command history for conversation: ${conversationId}`);
|
|
5053
4758
|
}
|
|
5054
4759
|
getCurrentDirectory(_conversationId) {
|
|
5055
4760
|
return this.currentDirectory;
|
|
@@ -5109,12 +4814,12 @@ Warnings:
|
|
|
5109
4814
|
if (useShell) {
|
|
5110
4815
|
cmd = "sh";
|
|
5111
4816
|
args = ["-c", command];
|
|
5112
|
-
|
|
4817
|
+
logger7.info(`Executing shell command: sh -c "${command}" in ${this.currentDirectory}`);
|
|
5113
4818
|
} else {
|
|
5114
4819
|
const parts = command.split(/\s+/);
|
|
5115
4820
|
cmd = parts[0];
|
|
5116
4821
|
args = parts.slice(1);
|
|
5117
|
-
|
|
4822
|
+
logger7.info(`Executing command: ${cmd} ${args.join(" ")} in ${this.currentDirectory}`);
|
|
5118
4823
|
}
|
|
5119
4824
|
let stdout = "";
|
|
5120
4825
|
let stderr = "";
|
|
@@ -5219,7 +4924,7 @@ Command timed out`,
|
|
|
5219
4924
|
} catch (err) {
|
|
5220
4925
|
const errText = String(err);
|
|
5221
4926
|
const warning = `Warning: PTY spawn failed (${errText}); retrying without PTY.`;
|
|
5222
|
-
|
|
4927
|
+
logger7.warn(`exec: PTY spawn failed (${errText}); retrying without PTY.`);
|
|
5223
4928
|
opts.warnings.push(warning);
|
|
5224
4929
|
}
|
|
5225
4930
|
}
|
|
@@ -5508,16 +5213,17 @@ ${String(err)}` : String(err);
|
|
|
5508
5213
|
// index.ts
|
|
5509
5214
|
var shellPlugin = {
|
|
5510
5215
|
name: "shell",
|
|
5511
|
-
description: "
|
|
5216
|
+
description: "Shell observability and history management providers",
|
|
5512
5217
|
services: [ShellService, ExecApprovalService],
|
|
5513
|
-
actions: [
|
|
5514
|
-
providers: [shellHistoryProvider]
|
|
5218
|
+
actions: [clearHistory],
|
|
5219
|
+
providers: [shellHistoryProvider, terminalUsageProvider]
|
|
5515
5220
|
};
|
|
5516
5221
|
var typescript_default = shellPlugin;
|
|
5517
5222
|
export {
|
|
5518
5223
|
validatePath,
|
|
5519
5224
|
truncateMiddle,
|
|
5520
5225
|
trimWithCap,
|
|
5226
|
+
terminalUsageProvider,
|
|
5521
5227
|
tail,
|
|
5522
5228
|
stripDsrRequests,
|
|
5523
5229
|
spawnWithFallback,
|
|
@@ -5539,7 +5245,6 @@ export {
|
|
|
5539
5245
|
recordAllowlistUse,
|
|
5540
5246
|
readEnvInt,
|
|
5541
5247
|
readApprovalsSnapshot,
|
|
5542
|
-
processAction,
|
|
5543
5248
|
pad,
|
|
5544
5249
|
normalizeSafeBins,
|
|
5545
5250
|
normalizeApprovals,
|
|
@@ -5565,7 +5270,6 @@ export {
|
|
|
5565
5270
|
formatSpawnError,
|
|
5566
5271
|
formatDuration,
|
|
5567
5272
|
extractBaseCommand,
|
|
5568
|
-
executeCommand,
|
|
5569
5273
|
evaluateShellAllowlist,
|
|
5570
5274
|
evaluateExecAllowlist,
|
|
5571
5275
|
ensureApprovals,
|
|
@@ -5595,4 +5299,4 @@ export {
|
|
|
5595
5299
|
BRACKETED_PASTE_END
|
|
5596
5300
|
};
|
|
5597
5301
|
|
|
5598
|
-
//# debugId=
|
|
5302
|
+
//# debugId=EB43D3D65D87A50A64756E2164756E21
|