Feature: Add persistent remote terminal MCP tools
Add terminal_open / terminal_exec / terminal_close so an AI can hold one shell session per Windows host and run a sequence of commands with cwd and environment preserved, instead of the one-shot exec_command. The persistent terminal is a separate full-command write capability gated by McpTerminal (default off) plus McpReadonly=0, with no whitelist and full audit. One device maps to one terminal session via the shared m_TermSessions map; idle sessions are swept after 300s. terminal_exec rejects commands that contain & or | (they corrupt the sentinel control-operator chain) as well as control characters. Also harden exec_command and terminal_exec against newline/CR injection, fix a dangling subCtx after an abrupt shell disconnect, and refresh lastActiveAt on command completion. Add en/zh-TW translations for the new UI strings and a design document covering both exec_command and the persistent terminal. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
// httplib 与 Windows 头部的 min/max 宏冲突,按 file_server.h 的既有约定处理。
|
||||
#undef min
|
||||
@@ -133,6 +134,29 @@ public:
|
||||
// 工具线程:清理终端挂起(发送失败等提前退出路径)。
|
||||
void ClearTermPending(uint64_t device_id);
|
||||
|
||||
// ===== P4:持久远程终端(terminal_open / terminal_exec / terminal_close)=====
|
||||
void SetTerminalEnabled(bool enabled) { m_terminalEnabled = enabled; }
|
||||
bool IsTerminalEnabled() const { return m_terminalEnabled; }
|
||||
|
||||
// 登记持久终端挂起(复用单设备单终端约束;sessionId 由调用方生成)。
|
||||
bool BeginTermOpen(uint64_t device_id, const std::string& sessionId);
|
||||
|
||||
// 复位单条命令字段并置 busy;输出 subCtx/isPty。false = 不存在/不匹配/未就绪/忙碌/已关。
|
||||
bool BeginTermCommand(uint64_t device_id, const std::string& sessionId,
|
||||
const std::string& command, const std::string& nonce,
|
||||
context*& subCtx, bool& isPty);
|
||||
|
||||
// 等待本条命令完成(done || closed || 超时)。done=保持会话;closed/超时=清理会话+路由。
|
||||
bool WaitTermCommand(uint64_t device_id, std::vector<BYTE>& out, int& exitCode,
|
||||
bool& closed, int timeoutMs);
|
||||
|
||||
// 关闭持久终端(校验 sessionId;CancelIO + 清理路由/会话)。
|
||||
// 返回:0=已关闭;1=会话不存在(幂等);2=sessionId 不匹配(调用方报错)。
|
||||
int CloseTermSession(uint64_t device_id, const std::string& sessionId);
|
||||
|
||||
// idle 回收:关闭 lastActiveAt 超时且非 busy 的持久会话。返回回收数量。
|
||||
int SweepIdleTerminals(time_t idleTimeoutSec);
|
||||
|
||||
// 安全配置(启动时由 CMy2015RemoteDlg 读 THIS_CFG 后设置)。
|
||||
void SetReadonly(bool readonly) { m_readonly = readonly; }
|
||||
void SetCmdWhitelist(const std::string& whitelist) { m_cmdWhitelist = whitelist; }
|
||||
@@ -185,6 +209,11 @@ private:
|
||||
int exitCode = -1;
|
||||
bool done = false; // 哨兵命中
|
||||
bool closed = false; // TOKEN_TERMINAL_CLOSE(进程退出)
|
||||
// ===== 新增(持久终端)=====
|
||||
std::string sessionId; // 持久会话 token(一次性 exec 为空)
|
||||
bool persistent = false;
|
||||
bool busy = false; // 一条命令在飞(terminal_exec 复位→WaitTermCommand 返回)
|
||||
time_t lastActiveAt = 0; // idle 回收用(秒)
|
||||
};
|
||||
std::mutex m_TermMutex;
|
||||
std::condition_variable m_TermCv;
|
||||
@@ -193,6 +222,7 @@ private:
|
||||
|
||||
bool m_readonly = true;
|
||||
std::string m_cmdWhitelist;
|
||||
bool m_terminalEnabled = false; // 持久终端开关(默认关;要求 m_readonly=false)
|
||||
};
|
||||
|
||||
// 全局访问器(仿 WebService(),见 WebService.h 末尾)
|
||||
|
||||
Reference in New Issue
Block a user