主题
本地代理服务
本文引用的源码文件
本文引用的文件
目录
引言
本地代理服务是 AI Helper 双进程架构中的 Node.js Agent 端,负责为 Chrome 扩展提供受控的本地文件系统访问、系统命令执行、长期记忆、RAG 检索、MCP 工具调用与技能管理。Agent 通过 HTTP API 和 WebSocket 暴露能力,并通过配对码 + Token 机制完成扩展与代理之间的认证绑定。
关键约束:
- 扩展端(Manifest V3)与 Agent 端(Node.js)版本号保持同步,当前以 2.3.1 为准。
- Agent 源码修改后必须重启进程,新接口才生效。
- 扩展端 Service Worker 存在生命周期硬约束,side panel 与 background 消息传递是常见故障点。
- 所有面向浏览器的响应需遵循 CORS 白名单策略,仅允许
chrome-extension://来源跨域读取。
章节来源
项目结构
Agent 入口为 agent/src/server.js,采用单文件路由 + 多模块职责分离的设计:
- HTTP 路由与请求处理集中在 server.js。
- 认证逻辑在 auth.js。
- 路径沙箱与命令分级在 security.js。
- 子进程命令执行与超时控制封装在 executor.js。
- 回收站逻辑在 trash.js。
- 配置加载、缓存与写锁在 config.js。
graph TB Client["浏览器扩展<br/>Chrome Extension"] --> HTTP["HTTP 服务器<br/>server.js"] Client --> WS["WebSocket 服务器<br/>server.js"] HTTP --> Auth["认证模块<br/>auth.js"] HTTP --> Security["安全模块<br/>security.js"] HTTP --> Executor["命令执行器<br/>executor.js"] HTTP --> Trash["回收站模块<br/>trash.js"] HTTP --> Config["配置模块<br/>config.js"] HTTP --> Memory["长期记忆路由<br/>memory/routes.js"] HTTP --> RAG["RAG 路由<br/>rag/routes.js"] HTTP --> MCP["MCP 注册表<br/>mcp/registry.js"] HTTP --> Skill["技能注册表<br/>skill/registry.js"]
图表来源
章节来源
核心组件
- HTTP 服务器:统一解析请求、CORS、国际化、认证拦截、路由分发、错误兜底。
- WebSocket 服务器:仅开放
/ws/exec/{execId},用于命令流式输出。 - 认证系统:配对码轮换、Token 验证、活跃连接窗口、失败锁定。
- 安全系统:路径白名单 + 硬阻止 + 符号链接校验;命令黑名单/灰名单/白名单三级管控。
- 命令执行引擎:shell 选择、子进程管理、stdout/stderr 流式广播、超时预算与延长策略、进程终止。
- 文件操作服务:读、写、列表、统计、删除、移动、重命名、下载、批量下载、流式下载、XLSX 预览。
- 回收站:软删除、元数据持久化、跨设备回退、7 天自动清理。
- 配置管理:默认值、内存缓存、mtime 刷新、写入互斥锁、敏感字段落盘混淆。
章节来源
- agent/src/server.js#L388-L425
- agent/src/server.js#L2086-L2153
- agent/src/auth.js#L30-L179
- agent/src/security.js#L109-L229
- agent/src/security.js#L691-L758
- agent/src/executor.js#L198-L386
- agent/src/trash.js#L166-L250
- agent/src/config.js#L107-L149
架构总览
Agent 的请求处理流程可概括为:
- 解析 Accept-Language,设置各模块语言。
- 处理 OPTIONS 预检,仅放行
chrome-extension://来源。 - 对无需认证的接口直接处理(配对、健康检查、本机关闭)。
- 对需要认证的接口校验 Bearer Token。
- 按 pathname 分发到文件、命令、Skill、MCP、Memory、RAG 等路由。
- 所有异常进入全局 catch,返回国际化错误。
sequenceDiagram participant Ext as "扩展" participant HTTP as "HTTP 服务器" participant Auth as "认证模块" participant Sec as "安全模块" participant Exec as "命令执行器" participant FS as "文件系统" Ext->>HTTP : "POST /api/exec" HTTP->>Auth : "验证 Bearer Token" Auth-->>HTTP : "extensionId 或拒绝" HTTP->>Sec : "checkCommand(command, force)" Sec-->>HTTP : "allow/confirm/deny" alt "deny" HTTP-->>Ext : "403 安全拒绝" else "confirm" HTTP-->>Ext : "200 需要确认" else "allow" HTTP->>Exec : "executeCommand(command, cwd)" Exec-->>HTTP : "execId + wsUrl" HTTP-->>Ext : "200 execId/wsUrl" Ext->>HTTP : "GET /api/fs/read" HTTP->>Sec : "checkPath(path)" Sec-->>HTTP : "allowed/resolved" HTTP->>FS : "readFile(resolved)" FS-->>HTTP : "content" HTTP-->>Ext : "200 content" end
图表来源
- agent/src/server.js#L427-L548
- agent/src/server.js#L1605-L1674
- agent/src/server.js#L1036-L1050
- agent/src/auth.js#L117-L127
- agent/src/security.js#L691-L758
- agent/src/executor.js#L198-L386
详细组件分析
HTTP 服务器与路由
HTTP 服务器承担以下职责:
- 构建 JSON 响应并设置 CORS 头,仅允许
chrome-extension://来源。 - 解析 JSON body,限制最大体大小。
- 解析 multipart/form-data 上传。
- 维护工作目录切换、允许路径增删。
- 提供文件读写、列表、统计、删除、移动、重命名、下载、批量下载、流式下载、XLSX 预览。
- 提供命令执行、停止、daemon 化。
- 提供 Skill、MCP、Memory、RAG 路由转发。
- 提供回收站恢复与列表。
- 提供审计日志查询。
- 启动 WebSocket 升级,仅接受
/ws/exec/{execId}。
关键路由分组:
- 无认证:
/api/pair、/api/status、/api/shutdown(远程仍需认证)、/api/heartbeat。 - 认证后:
/api/status/detail、/api/files/upload、/api/fs/*、/api/exec*、/api/trash/*、/api/logs/query、/api/skill/*、/api/mcp/*、/api/memory/*、/api/rag/*。
flowchart TD
Start(["请求进入"]) --> ParseI18n["解析语言并设置模块语言"]
ParseI18n --> OptionsCheck{"OPTIONS 预检?"}
OptionsCheck --> |是| AllowOrigin["仅放行 chrome-extension://"]
OptionsCheck --> |否| NoAuthRoutes["配对/状态/关闭/心跳"]
NoAuthRoutes --> AuthCheck["Bearer Token 校验"]
AuthCheck --> |失败| Reject["401/403"]
AuthCheck --> |成功| RouteDispatch["按 pathname 分发路由"]
RouteDispatch --> FsRoutes["文件操作"]
RouteDispatch --> ExecRoutes["命令执行"]
RouteDispatch --> MiscRoutes["Skill/MCP/Memory/RAG/日志/回收站"]
FsRoutes --> End(["返回 JSON 或二进制流"])
ExecRoutes --> End
MiscRoutes --> End
图表来源
- agent/src/server.js#L250-L303
- agent/src/server.js#L417-L548
- agent/src/server.js#L751-L862
- agent/src/server.js#L985-L1600
- agent/src/server.js#L1603-L1924
- agent/src/server.js#L1926-L2076
章节来源
- agent/src/server.js#L242-L266
- agent/src/server.js#L271-L303
- agent/src/server.js#L310-L383
- agent/src/server.js#L388-L425
- agent/src/server.js#L427-L548
- agent/src/server.js#L751-L862
- agent/src/server.js#L985-L1600
- agent/src/server.js#L1603-L1924
- agent/src/server.js#L1926-L2076
认证与安全系统
认证系统包含:
- 配对码生成与定时轮换。
- 连续失败锁定。
- Token 验证并更新最近活跃时间。
- 已配对扩展的 Token 存储于
pairings.json,落盘前混淆。
安全系统包含:
- 路径规范化、
~展开、绝对路径解析。 - 硬阻止目录(配置文件、配对记录、日志、回收站、内置技能状态)。
- 工作目录永远放行,但 realpath 仍做硬阻止校验。
- allowedPaths 白名单前缀匹配 + realpath 二次校验。
- 命令黑白灰名单,支持链式命令拆分、包装器剥壳、解释器内联载荷、命令替换扫描。
classDiagram
class Auth {
+setAuthLang(lang)
+startPairCodeRotation()
+stopPairCodeRotation()
+handlePairRequest(code, extensionId, tFn)
+verifyToken(token)
}
class Security {
+setSecurityLang(lang)
+normalizePathFormat(pathStr, platformOverride)
+checkPath(pathStr, tFn)
+checkCommand(command, force, tFn)
+isHardBlocked(normalizedPath, platformOverride)
+collectCommandScopes(command, depth, out)
}
class Config {
+loadConfig()
+saveConfig(config)
+updateConfigField(key, value)
+loadPairings()
+savePairing(extensionId, token)
}
Auth --> Config : "读取/保存配对"
Security --> Config : "读取 workdir/allowedPaths"
图表来源
- agent/src/auth.js#L14-L187
- agent/src/security.js#L15-L29
- agent/src/security.js#L40-L60
- agent/src/security.js#L109-L229
- agent/src/security.js#L691-L758
- agent/src/config.js#L107-L149
- agent/src/config.js#L215-L269
章节来源
- agent/src/auth.js#L30-L179
- agent/src/security.js#L62-L100
- agent/src/security.js#L109-L229
- agent/src/security.js#L285-L384
- agent/src/security.js#L691-L758
- agent/src/config.js#L107-L149
- agent/src/config.js#L215-L269
文件操作服务
文件操作服务覆盖完整生命周期:
- 上传:multipart 与流式上传,均做路径安全检查与大小限制。
- 读取:校验路径、目录判断、大小限制、UTF-8 或 base64。
- 写入:父目录创建、base64 解码、脚本权限剥离。
- 列表:递归枚举条目类型、大小、时间。
- 统计:权限、时间、MIME、符号链接标记。
- 删除:走回收站。
- 下载:单文件、目录 zip、批量 zip、流式下载。
- XLSX 预览:服务端解析前若干行,避免前端引入 SheetJS。
- 目录创建、重命名、移动:严格目标路径校验,防止静默覆盖。
flowchart TD
Req["文件请求"] --> CheckPath["checkPath 安全校验"]
CheckPath --> Allowed{"允许?"}
Allowed --> |否| Deny["403 安全拒绝"]
Allowed --> |是| OpType{"操作类型"}
OpType --> Read["读取文件"]
OpType --> Write["写入文件"]
OpType --> List["列出目录"]
OpType --> Stat["文件统计"]
OpType --> Delete["移动到回收站"]
OpType --> Download["下载/打包/流式下载"]
OpType --> Preview["XLSX 预览"]
OpType --> Rename["重命名"]
OpType --> Move["移动"]
Read --> Done["返回内容"]
Write --> Done
List --> Done
Stat --> Done
Delete --> Done
Download --> Done
Preview --> Done
Rename --> Done
Move --> Done
图表来源
章节来源
命令执行引擎
命令执行引擎负责:
- 平台 shell 选择:Windows Git Bash/cmd/PowerShell,macOS zsh/bash,Linux bash/sh。
- 子进程标准输出/错误输出流式广播。
- 输出缓冲区上限截断。
- 超时策略:基础超时、有输出则延长、最多延长次数、总预算封顶。
- 进程终止:Unix 进程组 SIGTERM/SIGKILL,Windows taskkill /T /PID。
- WebSocket 回放:已完成进程输出缓存,延迟连接客户端可回放。
- daemon 化:显式 detach 豁免超时。
sequenceDiagram participant API as "/api/exec" participant Sec as "checkCommand" participant Exec as "executeCommand" participant Proc as "child_process" participant WS as "WebSocket" API->>Sec : "command, force" Sec-->>API : "allow/confirm/deny" alt "deny" API-->>Client : "403 deny" else "confirm" API-->>Client : "200 confirm" else "allow" API->>Exec : "spawn shell + command" Exec->>Proc : "stdout/stderr pipe" Proc-->>Exec : "data chunks" Exec-->>WS : "stdout/stderr broadcast" Proc-->>Exec : "close/error" Exec-->>WS : "exit/killed/timedOut" end
图表来源
- agent/src/server.js#L1605-L1674
- agent/src/executor.js#L32-L91
- agent/src/executor.js#L198-L386
- agent/src/executor.js#L429-L549
章节来源
- agent/src/executor.js#L32-L91
- agent/src/executor.js#L118-L156
- agent/src/executor.js#L165-L186
- agent/src/executor.js#L198-L386
- agent/src/executor.js#L429-L549
回收站功能
回收站实现软删除:
- 移动到
~/.ai-helper-agent/.trash/。 - 记录原始路径、名称、大小、删除时间、是否目录。
- 跨设备 rename 失败时回退复制+删除源。
- 7 天 TTL 自动清理。
- 每 6 小时定期清理。
- 恢复时检查原路径是否被占用。
flowchart TD
DeleteReq["删除请求"] --> TrashMove["moveToTrash"]
TrashMove --> CrossDevice{"同设备?"}
CrossDevice --> |是| Rename["rename 瞬时移动"]
CrossDevice --> |否| CopyDelete["cp + rm 源"]
Rename --> Meta["写入 metadata.json"]
CopyDelete --> Meta
Meta --> Periodic["周期清理过期条目"]
Restore["恢复请求"] --> FindEntry["查找 trashId"]
FindEntry --> Exists{"原路径可用?"}
Exists --> |否| Error["返回错误"]
Exists --> |是| MoveBack["移回原路径"]
MoveBack --> CleanMeta["删除元数据"]
图表来源
- agent/src/server.js#L1144-L1161
- agent/src/server.js#L1693-L1703
- agent/src/trash.js#L141-L250
- agent/src/trash.js#L263-L284
章节来源
- agent/src/server.js#L1144-L1161
- agent/src/server.js#L1693-L1703
- agent/src/trash.js#L141-L250
- agent/src/trash.js#L263-L284
WebSocket 通信
WebSocket 仅开放 /ws/exec/{execId}:
- 升级前解析 URL。
- 认证优先 Authorization Header,回退 query token。
- 将客户端加入运行中进程的监听集合。
- 心跳 ping/pong 检测半开连接。
- 断开连接后按受管模式与旧语义分别处理超时。
sequenceDiagram
participant Client as "扩展"
participant Server as "HTTP 服务器"
participant WSS as "WebSocketServer"
participant Exec as "executor"
Client->>Server : "upgrade /ws/exec/{execId}"
Server->>Server : "verifyToken(token)"
alt "认证失败"
Server-->>Client : "403 Forbidden"
else "认证成功"
Server->>WSS : "handleUpgrade"
WSS->>Exec : "addWsClient(execId, ws)"
Exec-->>WSS : "true/false"
WSS->>Client : "开始流式 stdout/stderr"
Client->>WSS : "ping/pong"
WSS->>Exec : "disconnectWsClient on close"
end
图表来源
章节来源
依赖关系分析
Agent 包依赖:
ws:WebSocket 服务器。archiver:ZIP 打包。xlsx:Excel 预览。@modelcontextprotocol/sdk:MCP 协议。zod:运行时校验。- RAG 可选依赖:vectra、transformers、pdf-parse、mammoth、officeparser、cheerio。
Agent 内部模块依赖:
- server.js 依赖 auth、security、executor、trash、config、search、rag、memory、mcp、skill、logger、process-tree、i18n。
- executor.js 依赖 config、i18n。
- security.js 依赖 config、i18n。
- trash.js 依赖 i18n、sys-lang。
- auth.js 依赖 config、i18n、sys-lang。
- config.js 依赖 crypto-lite、i18n。
graph LR Server["server.js"] --> Auth["auth.js"] Server --> Security["security.js"] Server --> Executor["executor.js"] Server --> Trash["trash.js"] Server --> Config["config.js"] Server --> Search["search.js"] Server --> RAG["rag/*"] Server --> Memory["memory/*"] Server --> MCP["mcp/*"] Server --> Skill["skill/*"] Server --> Logger["logger.js"] Server --> ProcessTree["process-tree.js"] Server --> I18n["i18n.js"]
图表来源
章节来源
性能与容量特性
- 请求体大小限制:JSON body 与 multipart 均限制为 200MB。
- 文件读取/下载默认大小限制:50MB,可通过配置调整。
- 流式上传:200MB,按字节计数保护。
- 命令输出缓冲区上限:5MB,超限后广播截断提示。
- 搜索最大结果数:5000。
- 流式下载分块:64KB,使用
setImmediate或drain让出事件循环。 - 超时策略:基础超时、有输出延长、最多 5 次延长、总预算封顶 600s。
- 配置缓存:mtime 命中返回内存对象,减少磁盘 IO。
- 回收站清理:每 6 小时一次,避免长时间运行积累垃圾。
章节来源
- agent/src/server.js#L132-L136
- agent/src/server.js#L271-L303
- agent/src/server.js#L310-L383
- agent/src/server.js#L792-L862
- agent/src/server.js#L1267-L1385
- agent/src/executor.js#L93-L116
- agent/src/executor.js#L165-L186
- agent/src/config.js#L43-L51
- agent/src/config.js#L107-L149
- agent/src/trash.js#L38-L39
部署与配置指南
安装与启动
- 官方安装渠道为 GitHub Releases 自动构建产物。
- npm 包名为
ai-helper-agent,版本 2.3.1。 - 入口文件为
agent/src/server.js,bin 命令为ai-helper-agent与别名aha。 - 要求 Node.js >= 18。
章节来源
- agent/package.json#L1-L10
- agent/package.json#L44-L46
- docs/articles/promo-series/03-进阶玩法/04-本地代理服务.md#L25-L55
环境变量与端口配置
- 默认端口:18910。
- 默认主机:127.0.0.1。
- 工作目录:
~/.ai-helper-agent/workspace。 - 允许路径:默认包含工作目录。
- 配对码 TTL:默认 30 秒。
- 命令超时:默认 300000ms。
- 文件最大读取大小:默认 50MB。
- RAG URL 内网访问策略:默认关闭私有网络访问。
- 长期记忆 embedding:默认关闭,mode 可为 openai-compat 或 local。
章节来源
SSL 证书配置
当前 Agent 使用原生 http.createServer,未内置 HTTPS 支持。若需 TLS:
- 建议在前置反向代理(如 Nginx、Caddy)配置 SSL 终止。
- Agent 仅监听本地或可信网络地址,避免直接暴露公网。
- 若未来改为 HTTPS,需确保 CORS、Token、WebSocket upgrade 链路一致。
[本节为通用部署建议,不直接分析具体源码文件]
防火墙规则
- 推荐仅开放本地回环地址。
- 如需远程访问,应通过防火墙限制来源 IP 段。
- 注意
/api/shutdown远程来源仍需认证,但仍建议最小化暴露面。
章节来源
安全最佳实践
- 始终启用 Bearer Token 认证,避免无认证接口被恶意网页读取。
- 仅允许
chrome-extension://作为 CORS 来源。 - 使用
allowedPaths精确限定可访问目录,不要随意扩大白名单。 - 避免将 Agent 工作目录设为
.ai-helper-agent自身。 - 谨慎使用
force参数,它只能跳过灰名单,不能绕过黑名单。 - 监控审计日志,关注
exec_denied、fs_*_blocked、auth_invalid。 - 定期清理回收站,避免磁盘膨胀。
- 对脚本类文件上传/写入后,Agent 会剥离执行权限,但仍应避免从不可信来源直接执行脚本。
- RAG 依赖安装与 Agent 在线更新互斥,避免并发写 node_modules。
章节来源
- agent/src/server.js#L242-L266
- agent/src/server.js#L537-L548
- agent/src/security.js#L62-L100
- agent/src/security.js#L109-L229
- agent/src/security.js#L691-L758
- agent/src/server.js#L605-L720
故障诊断指南
常见问题定位
- 端口占用:服务器启动报错
EADDRINUSE,退出进程。 - 配对失败:检查配对码是否轮换、扩展 ID 是否正确、失败锁定是否触发。
- Token 无效:检查
Authorization: Bearer <token>是否正确。 - 文件路径被拒:检查
allowedPaths、workdir、符号链接、硬阻止目录。 - 命令被拒:查看
level=deny原因,确认是否命中黑名单。 - 命令超时:检查输出流是否有数据,受管模式下无输出会被判定挂起并杀死。
- WebSocket 断连:检查心跳 ping/pong,确认插件端 SW 保活。
- RAG 不可用:调用
/api/rag/detect查看探测错误,必要时重新安装依赖。
日志与审计
- 审计日志分类:认证、文件、命令、安全、系统。
- 日志查询接口:
/api/logs/query,默认最近 7 天,单次最多 500 条。 - 前台运行时日志实时输出到终端。
- 全局未捕获异常与未处理 Promise 拒绝会被记录但不退出进程。
章节来源
- agent/src/server.js#L2155-L2163
- agent/src/server.js#L1705-L1725
- agent/src/server.js#L2293-L2306
- agent/src/auth.js#L138-L179
- agent/src/executor.js#L165-L186
- agent/src/server.js#L2086-L2153
结论
本地代理服务通过 HTTP + WebSocket 将浏览器扩展的能力扩展到本地文件系统与命令行,同时以路径沙箱、命令分级、Token 认证、审计日志构成多层安全边界。其设计强调可控性:工作目录与白名单控制文件范围,黑名单绝对禁止高危命令,灰名单要求用户确认,回收站提供后悔空间,超时与进程树终止保障资源安全。部署时应遵循最小暴露原则,结合反向代理与防火墙规则,配合审计日志进行持续监控。