@@ -1314,7 +1314,102 @@ interface IErrorInfo
13141314// 注册工具
13151315registerTool ( diagnosticTop5Errors ) ;
13161316
1317+ // 12. 沙盒执行 Lua/Python 代码
1318+ export const sandboxRun : Tool = {
1319+ name : 'sandbox_run' ,
1320+ description : `在沙盒环境中执行 Lua 或 Python 代码,并返回标准输出、标准错误。禁止访问文件系统。` ,
1321+ parameters : {
1322+ type : 'object' ,
1323+ properties : {
1324+ language : { type : 'string' , description : '执行语言(lua 或 python)' } ,
1325+ code : { type : 'string' , description : '要执行的代码内容。' } ,
1326+ input : { type : 'string' , description : '可选的标准输入内容(stdin)。' }
1327+ } ,
1328+ required : [ 'language' , 'code' ] ,
1329+ } ,
1330+ function : async ( args : { language : 'lua' | 'python' ; code : string ; input ?: string } ) => {
1331+ const strLanguage : string = args . language ;
1332+ const strCode : string = args . code ;
1333+ const strInput : string = args . input ?? '' ;
1334+
1335+ try
1336+ {
1337+ // 简单敏感词检测
1338+ const arrForbidden : string [ ] = [ 'os.' , 'io.' , 'open(' , 'require(' , 'import os' , 'import shutil' ]
1339+ for ( const strBad of arrForbidden )
1340+ {
1341+ if ( strCode . includes ( strBad ) )
1342+ {
1343+ return `安全警告:代码中包含禁止的调用 (${ strBad } )`
1344+ }
1345+ }
1346+
1347+ let strCommand : string = '' ;
1348+ let arrArgs : string [ ] = [ ] ;
1349+
1350+ if ( strLanguage === 'lua' )
1351+ {
1352+ strCommand = 'lua' ;
1353+ arrArgs = [ '-e' , strCode ] ;
1354+ }
1355+ else if ( strLanguage === 'python' )
1356+ {
1357+ strCommand = 'python' ;
1358+ arrArgs = [ '-c' , strCode ] ;
1359+ }
1360+ else
1361+ {
1362+ return `不支持的语言类型: ${ strLanguage } `
1363+ }
1364+
1365+ return await new Promise < string > ( ( resolve , reject ) =>
1366+ {
1367+ const objChild = childProcess . spawn ( strCommand , arrArgs , { stdio : [ 'pipe' , 'pipe' , 'pipe' ] } ) ;
1368+
1369+ let strStdout : string = '' ;
1370+ let strStderr : string = '' ;
1371+
1372+ objChild . stdout . on ( 'data' , ( data ) => {
1373+ strStdout += data . toString ( ) ;
1374+ } ) ;
1375+
1376+ objChild . stderr . on ( 'data' , ( data ) => {
1377+ strStderr += data . toString ( ) ;
1378+ } ) ;
1379+
1380+ objChild . on ( 'error' , ( error ) => {
1381+ reject ( `执行出错: ${ error . message } ` ) ;
1382+ } ) ;
1383+
1384+ objChild . on ( 'close' , ( code ) => {
1385+ resolve ( JSON . stringify ( {
1386+ exitCode : code ,
1387+ stdout : strStdout . trim ( ) ,
1388+ stderr : strStderr . trim ( ) ,
1389+ } , null , 4 ) ) ;
1390+ } ) ;
1391+
1392+ // 写入标准输入
1393+ if ( strInput . length > 0 )
1394+ {
1395+ objChild . stdin . write ( strInput )
1396+ }
1397+ objChild . stdin . end ( ) ;
1398+
1399+ // 超时保护(3秒)
1400+ setTimeout ( ( ) => {
1401+ objChild . kill ( 'SIGKILL' ) ;
1402+ } , 3000 ) ;
1403+ } ) ;
1404+ }
1405+ catch ( error : any )
1406+ {
1407+ return `沙盒执行失败: ${ error . message } ` ;
1408+ }
1409+ } ,
1410+ }
13171411
1412+ registerTool ( sandboxRun )
13181413
13191414
13201415
0 commit comments