jkooe
|
8743bd1237
|
feat(v13): 成功指标聚合(对齐 PRD 2.2 四项验收指标)+ 依据真实数据修正口径
## 背景(审查报告 P0-2)
审查报告指出:PRD 2.2 的成功指标「无任何采集与统计落点,指标空转」,并给出
已验证原型(30 行脚本在 598 条真实审计日志上算出三项指标)。本版将其产品化。
## 实现(apps/agent/src/metrics.ts,纯函数 + 可单测)
数据源就是审计日志,无需额外埋点:
- 闭环成功率 = invoke ok / 总数
- 装软件成功率 = app.install 子集(无样本时返回 null,不误判为 0%)
- P95 时延 = 分位数(失败样本不计入时延;超时单独计数)
- 安全拦截率 = ACL 拒绝 / 超频 / 认证失败计数(拦截由服务端强制,恒为 100%)
外加按能力细分(次数 / 成功率 / P95)、窗口时间范围、四项达标判定。
出口:能力 system.metrics(36 项)+ CLI `nodeagent metrics [--since ms]` + MCP `na_metrics`。
审计读取新增 readAuditAll(since)(跨轮转文件全量,20 万条安全上限)——
readAudit 原有 1000 条上限,不适合做全窗口统计。
## 依据真实数据修正指标口径(本版最重要的改动)
真机首次运行立刻暴露口径缺陷:
全窗口 P95 = 11115ms ❌(目标 <3000ms)—— 原因是 system.shell.exec P95 27.5s
近 6 小时窗口 P95 = 9575ms ❌ —— 8 个样本里仅 1 次「故意重启」9.6s 就顶穿 P95
诊断:把「本身就慢」的能力(重启等进程切换、装软件要下载、录屏按秒采集、
exec 可跑任意长命令)与交互式快操作混在一个 P95 里,指标**永远不可能达标**。
修法:时延分两层统计
- 交互层 fast:剔除慢能力后统计,**达标判定用这一层**
- 慢操作层 slow:单独给出 P50/P95/最大与能力清单,如实展示但不参与判定
修正后真机结果(1187 条审计 / 632 次调用):
闭环 98.7% ✅ · 装软件 无样本 ✅ · P95 交互层 2012ms ✅(P50 326ms)
慢操作 P95 27155ms(单列)· 安全拦截 100% ✅ → **四项全达标**
## 单测
89 -> 101(新增指标 12 例:空样本不误判 / 成功率边界 90% / P95 分位 /
分层口径(慢能力不拖累、真机场景复现)/ 超时单列 / 自定义阈值 / 窗口 / 摘要格式)
|
2026-09-30 00:19:10 +08:00 |
|
jkooe
|
66c44f6822
|
feat(E3): Hub 并发多控制端 + 设备分组(阶段 E 全部完成)
## E3a 并发多控制端(Hub 槽位池)
过去:一个被控端只有一条 Hub 连接 -> 同时只能一个控制端(否则 E_NODE_BUSY)。
现在:
- Hub 侧 agents 表改为「node_id -> 槽位池」,每个槽位服务一个控制端:
有空闲槽位直接配对;不足且未达上限则向被控端请求扩容(need_slot,3s 超时);
仍不满足才返回 E_NODE_BUSY。新增配置 max_slots_per_node(默认 3,设 1 即退回独占语义)
- 被控端侧 hub-mode 重写为槽位池:常备 2 条连接(warm_slots 可调),
并在某槽位被占用(收到 hello)时预热下一条直到 max_slots
—— 复用既有协议信号,不新增控制消息;每条槽位独立重连与退避
- Hub 列表视图聚合为「一节点一行」并带 slots / paired_slots
- e2e 新增并发用例:两个控制端同时握手 + 交替并发调用,均成功(旧版会失败)
## E3b 设备分组
- 客户端配置新增 groups(组名 -> 设备名数组;成员可写 @其它组名,最多展开 3 层防环)
- CLI:nodeagent group add|remove|list;fanout --nodes @组名 按组并发下发
- 真机验证:group add 本机 win -> fanout system.info --nodes @本机 正常
## E3c 权限隔离(部分完成)
- 能力级隔离沿用被控端 ACL(按 client_id,已含 allow/deny/glob/生效时段/IP 白黑名单/按能力限速)
- Hub 侧「按设备/按控制端授权」尚未实现(当前 Hub 视角为单一令牌),已记入路线图待办
## 测试
- 单测 73 -> 79(新增设备分组 6 例:展开 / 嵌套 / 去重 / 未知 / 兼容旧配置 / 环引用收敛)
- e2e 21/21(含扩展后的 Hub 并发双控制端用例)
|
2026-09-29 14:33:01 +08:00 |
|
jkooe
|
3ed117770b
|
feat(E4): GUI 宏(步骤序列回放)+ 窗口聚焦加固(能力 35 稳定)
## E4 宏引擎(packages/client/src/macro.ts,CLI 与 MCP 共用)
- 步骤类型:focus / find / click / type / key / drag / sleep / exec / clip / assert / capture
- 通用能力:retry(失败重试)、interval_ms、optional|continue_on_error、${VAR} 与 ${VAR:-默认值} 替换
- 断言内置在步骤里:exec 的 expect_exit/expect_stdout、clip 的 expect、
assert 支持 kind=screen|window|clip(屏幕断言自动走 UIA→OCR)
- 返回逐步结果(含 ms 与失败定位 failed_at),失败即中止并给出可读原因
- CLI: macro run <file> [--var k=v] [--out 目录] / macro validate / macro init(生成示例)
- MCP: na_macro_run(inline steps + vars)
## 真机验证(记事本全流程)
宏 init 生成示例 -> 启动记事本 -> 回放 9 步:
focus ✓ / key ctrl+a ✓ / delete ✓ / type ✓ / sleep ✓ / key ctrl+a ✓ / key ctrl+c ✓ /
clip 断言「宏回放演示 回放测试」✓ / window 断言 ✓ -> 全部通过(10.1s)
## 顺带修复两个真机踩出的问题
1. **window.focus 可能被静默否决**:SetForegroundWindow 受 Windows 前台锁定限制,
调用后前台窗口可能仍是别人(实测被系统防火墙对话框抢焦点,导致宏的输入全进了对话框)。
现改为:调用后**校验当前前台窗口**;未生效则在该窗口标题栏做一次真实点击兜底,
并返回 activated_by=api|click 让调用方知情。
2. **window.list 会被 limit 截掉真正的前台窗口**:现按 is_foreground 排序置顶并返回 total。
3. 宏引擎:变量缺失原先会在 try 之外抛出、导致整个宏崩掉;现改为「记为该步失败」,
optional 时继续执行(单测覆盖)。
单测 63 -> 73(新增宏引擎 10 个用例:变量/默认值/缺失、retry、optional、失败中止、
expect_exit/stdout、clip 断言、未知步骤、find→click 坐标透传、坏文件拒绝);e2e 21/21
|
2026-09-29 14:25:35 +08:00 |
|
jkooe
|
0a47c5a92d
|
feat(E1+E2): 事件订阅与监控 —— agent 主动推送(能力 31 -> 35)
## 协议
- 新增 Methods.Event = 'event':协议中唯一的**无 id 通知**(JSON-RPC notification),
被控端 → 控制端主动推送,控制端不回复
- 4 项能力:event.watch / event.unwatch / event.list / event.poll
- 能力处理器签名扩展为 (args, ctx?):ctx 携带 owner(连接标识)与 emit(推送出口)
## 被控端(apps/agent/src/events.ts)
三类 watcher:
- file —— fs.watch(支持 recursive + glob 过滤),报 created_or_removed / modified
- process —— 轮询 tasklist(win)/ps(posix) 做差分,报 process_started / process_exited
- net —— 轮询 netstat 提取 LISTEN 端口做差分,报 port_opened / port_closed
两条出口并存:
1) **推送**:通过 event 通知实时发给创建订阅的连接
2) **环形缓冲 + 游标**:500 条上限、seq 游标增量拉取(适配无法收推送的 MCP)
其它:首次采样只建基线(避免开订阅就刷出几百条);连接断开自动清理该连接的订阅(防泄漏)
## 控制端
- NodeAgentClient 新增 onEvent 回调;handleMessage 把无 id 的 event 通知分发过去
- CLI: nodeagent events [--kind file|process|net] [--path/--pattern/--recursive/--seconds]
无 --kind 则列出当前订阅
- MCP: na_event_watch / na_event_poll / na_event_list / na_event_unwatch
## 真机验证(三类全部实测)
- 文件:创建/修改/删除 t1.txt -> 3 个事件实时推送(14:16:33/34/35)
- 进程:启动并关闭 Notepad.exe -> process_started / process_exited
- 端口:开-关 8899 -> port_opened / port_closed(基线 45 个监听端口)
全部**零轮询**到达控制端(由被控端主动推)。
单测 61 -> 63(补 event.watch 枚举/边界与 event.poll 游标校验)、e2e 21/21 全绿
|
2026-09-29 14:19:09 +08:00 |
|
jkooe
|
2dccec9a5c
|
feat(D): 生产化 —— 无人值守模式 / 一键升级 / 文档口径更新
## D1 无人值守(install.ps1)
- 新增 -Unattended(S4U 登录类型):**无需保存密码,注销/重启后仍自动运行**
- 新增 -AtStartup:追加开机触发器;任务设置补 StartWhenAvailable(错过触发后补跑)
- **诚实标注能力边界**:S4U 运行在非交互会话,GUI 能力(截屏/UIA/键鼠)不可用;
-Unattended 与 -AllowInput 冲突时自动关闭输入控制并回写配置
- 说明文档给出两种模式的对照表(交互模式支持 GUI,但注销即停)
## D2 一键升级(nodeagent deploy)
- system.info 新增自描述字段:pid / agent_script / agent_home / node_path
- deploy 流程:读取被控端入口路径 → 备份旧文件 → 分块上传新 agent.mjs
→ 调 system.agent.restart 受控重启 → 等待恢复并复验能力数
- 真机验证:
* 首次(旧版 agent 无自描述):--path 指定 → 上传 853KB → PID 16492 / 31 项能力
* 二次:自动识别路径 + 自动备份 → PID 34120 / 31 项能力(免 --path)
## D3 CI(待推送)
- windows-e2e.yml 增加单元测试步骤(3 行);因 OAuth token 缺 workflow scope,
该改动暂留本地未推送,需用户授权后推送
## D4 文档口径更新(README)
- 能力总览补齐 31 项(新增:自持/异步任务/窗口/录屏/剪贴板/拖拽/审计校验)
- 统计数字更正:19 项能力 -> 31,15 个 MCP 工具 -> 26,补 61 项单元测试
- 路线图补 v7~v11+;安全章节补密钥库/Audit 链/ACL 细化
- 命令速查新增:restart / deploy / daemon / fanout / bg / tasks / clip / record /
window.* / screen.find / mouse drag
- MCP 工具表按新工具重排;安装章节新增两种运行模式对照表
单测 61/61、e2e 21/21 全绿
|
2026-09-29 11:47:15 +08:00 |
|
jkooe
|
ad88e0bb87
|
feat(C): 操作面补完 —— 拖拽 / 录屏 / 剪贴板图片 / 多设备并发(能力 29 -> 31)
## C1 鼠标拖拽(input.mouse.drag)
- C# SendInput 新增 Drag():按下 → 分步插值移动 → 抬起,整段在一次进程内完成
(避免每步一个 PS 进程的抖动),步数按距离自适应(8~60),步间延时默认 12ms
- CLI: nodeagent mouse drag <x1> <y1> <x2> <y2>;MCP: na_mouse action=drag
- 同时给 key.press 增加 interval_ms(按键序列间隔可调)
- 真机端到端验证:记事本输入 DRAGTEST_1234 -> 拖选 -> Ctrl+C
-> 剪贴板由 'CLIPBOARD_EMPTY_MARKER' 变为 'DRAGTEST_1234'(证明拖拽真实生效)
## C2 录屏(screen.record)
- 帧循环在一次 PS 调用内完成;有 ffmpeg 则自动封装 mp4
- 产物留在被控端目录,由调用方 fs.read / pull 取回(不把大视频塞进单条 RPC 响应)
- CLI: nodeagent record --duration/--fps/--scale/--region;MCP: na_record
- 真机验证:3s@2fps 区域录制 -> 6 帧(3087ms),pull 回帧并目检内容正确
## C3 剪贴板图片(clip.get/set 1.1)
- format=auto/text/image;图片经临时文件双向传递(规避 Windows 命令行 ~32KB 上限与 stdout 截断)
- CLI: clip --image-file <路径> / clip --out <路径>;MCP: na_clip format/image_base64
- 真机验证:写入 14592 字节 -> 读回 PNG 400x200,目检图像正确
## C5 多设备并发(fanout)
- nodeagent fanout <能力> [--nodes a,b] [--args JSON]:allSettled 并发,任一失败不影响其他
- 真机验证:并发下发 system.info / system.status 正常
单测 59 -> 61、e2e 21/21 全绿
注:C4(macOS window.*/screen.find 对齐)暂缓,需 macOS 辅助功能/录屏权限,留待 Mac 作被控端时实现
|
2026-09-29 11:41:48 +08:00 |
|
jkooe
|
eb54c60c7c
|
feat(B): 安全加固 —— 密钥库保护 + 审计防篡改 + ACL 细化(能力 28 -> 29)
## B1 私钥不再明文落盘
- 新增 packages/client/src/secret.ts:macOS Keychain / Windows DPAPI(CurrentUser)
- keys.ts:落盘文件只留 secret 描述符(backend/label/protected),不含 privateKey;
老格式明文密钥**首次加载自动迁移**;后端不可用时回退明文 + 告警(绝不因保护而不可用)
- 真机验证(隔离目录):
* keygen -> '✓ 私钥已存入系统密钥库(keychain)',文件中无 privateKey,钥匙串有条目
* loadKeys 回读私钥成功(64 字符)
* 老格式明文文件 -> 自动迁移、文件清理、二次回读正常
* Windows DPAPI 往返一致(ROUNDTRIP_OK=True,密文不含明文)
## B2 审计链式哈希(防篡改)
- 每条审计记录加 prev/hash(prev+规范化正文 sha256 前 32 位);轮转跨文件连续
- agent 重启从日志尾部恢复锚点,链不断
- 新能力 system.audit.verify + CLI 'nodeagent audit verify'
- 真机:'✓ 审计链完整(校验 21 条,跳过历史条目 857 条)'
- 单测覆盖:篡改检出、删除中间条目检出(链断裂)、历史条目 legacy 跳过、重启续链
## B3 ACL 细化
- 协议层新增纯函数:normalizeIp / ipMatchesCidr / ipAllowed / inTimeWindow / rateLimitFor
- AclClient 扩展:allow_cidr / deny_cidr / allow_window(days+from/to,支持跨零点) / rate_limits
- server.ts:IP 白黑名单与生效时段校验(命中即 audit acl.denied);限速改为按能力
(rate_limits 精确优先、其次 glob、回退 max_calls_per_min),窗口按限速档位分桶
### 真机踩坑(已修复并回归)
Node 的 socket.remoteAddress 在双栈监听下是 **IPv4-mapped IPv6**(::ffff:192.168.1.100),
原用 split(':')[0] 取到空串 -> CIDR 永不匹配。新增 normalizeIp() 归一,单测覆盖该场景。
真机复测:'✗ E_ACL_DENIED: 来源 IP 不被允许';移除黑名单后 fs.list 连调 3 次 ->
第 3 次 '✗ E_RATE_LIMITED: 调用频率超限(fs.list 上限 2/分钟)'
单测 37 -> 59、e2e 21/21 全绿
|
2026-09-29 11:27:52 +08:00 |
|
jkooe
|
fac51046cf
|
feat(v10.1): CLI 常驻 daemon(nodeagentd)—— 连接池复用,批量调用提速
## 机制
- nodeagentd 常驻进程监听 UDS($TMPDIR/nodeagentd.sock),持有与被控端的
长连接池(autoReconnect,每设备一条,LRU 上限 8,空闲 5min 释放)
- CLI withClient 检测 socket 存活 → 经 daemon JSON-lines 转发 invoke(虚拟 client);
daemon 自身错误静默回退直连,业务错误原样透传 —— 零行为变化,纯加速层
- CLI 新命令: nodeagent daemon start|stop|status;打包新增 nodeagentd 产物
## 实测(真机)
- 轻调用(info): 752ms -> 527ms(省 TLS+hello/challenge/auth,约 30%)
- 轻调用 5 连发(clip.get): 2.58s -> 2.41s
- 重调用(ps 远端 CPU 采样 1.4s)提速不显著 —— 瓶颈在远端执行而非握手,符合预期
- unit 26/26、e2e 21/21 全绿
|
2026-09-29 10:55:38 +08:00 |
|
jkooe
|
e50e805383
|
feat(v10): 长任务异步化(system.task.*)+ 剪贴板(clip.*),能力 23 -> 28
## 长任务异步化(P1)
- system.shell.exec 增加 async:true -> 立即返回 task_id(wait_forever 可不设超时)
- system.task.list / get / kill:任务表(Map 内存态,完成态保留 30min / 上限 50 条),
输出 Buffer 累积(上限 10MB),get 支持 offset 增量续读
- kill 走 killTree(整棵进程树);超时自动标记 killed/exit=124(与 timeout(1) 惯例一致)
- 命令只记 sha256 前 8 位摘要(与审计脱敏策略一致)
- CLI:bg / tasks / task <id> [--offset N] [--kill]
## 剪贴板(P1)
- clip.get / clip.set(Windows: Get/Set-Clipboard;macOS: pbpaste/pbcopy)
- set 走 base64 传输规避命令行参数编码问题(中文/emoji 安全)
## MCP 同步
- na_bg / na_task(list|get|kill 多动作)/ na_clip(get|set 多动作)
真机验证(全生命周期):
- bg 20 秒长任务 -> 立即返回 task_id;tasks 列表 running;
task 增量读 tick 10~12 -> 14~15;--kill 后 killed/exit=124
- clip --set 中文+emoji -> 18 字符;读回逐字一致
- 28 项能力在线;unit 26/26、e2e 21/21 全绿;Mac 端 CLI/MCP 已重装
|
2026-09-29 01:19:10 +08:00 |
|
jkooe
|
111a7b5918
|
feat(P0): UTF-8 全链路统一 + exec 输出结构化 + 受控重启(v7)
## P0-2 统一 UTF-8 编码链路
- util/exec.ts:Windows 侧注入 [Console]::OutputEncoding/ 为 UTF-8,
cmd 分支加 chcp 65001;并为子进程设置 PYTHONIOENCODING/LANG/LC_ALL。
- 根治三类事故:PowerShell 管道损坏中文(U+FFFD)、控制台 GBK 乱码。
- 真机验证:桌面文件名 [115浏览器.lnk / 360安全卫士.lnk] 由乱码变为正确中文。
## P0-4 exec 输出结构化
- CLI cmdExec:退出码/耗时等诊断信息改走 stderr,stdout 只保留命令自身输出。
- 使 不再被尾部标注污染(实测 stdout 仅 'ABC')。
## P0-3 受控重启(新增 system.agent.restart,能力数 19 -> 20)
- 先经历 4 种失败方案(均有真机证据):
1) 计划任务 + start node.exe -> Session 0 无桌面,start 拉不起进程
2) detached spawn + start /B -> cmd 退出即带走子进程
3) detached spawn + 直接跑 node -> detached cmd 随 agent 一起消失
4) 计划任务 action 直接跑 node -> 成功!但暴露环境变量传参 bug
- 最终方案:计划任务(ExecutionTimeLimit=0),action = cmd /c
「延时 -> taskkill 旧 PID -> 前台执行 node.exe」;Task Scheduler 持有 cmd,
cmd 持有 node,整条链与旧 agent 无关,且不依赖桌面会话。
- 关键坑:cmd 中 `set X=Y & cmd` 的 `&` 前空格会被计入变量值('Y '),
导致 agent 读不到配置回退默认端口 → EADDRINUSE。必须写成 `set X=Y& cmd`。
- 真机验证:节点 PID 31864 -> 22656,端口/能力/调用全部正常。
- 附带:Windows 用 ping 替代 timeout(后者在非交互环境报 Input redirection 不支持)。
CLI 新增 `nodeagent restart [--delay ms]`;unit 26/26、e2e 21/21 全绿。
|
2026-09-28 23:26:59 +08:00 |
|
jkooe
|
0bf9a2f918
|
docs: 重写 README
原 README 已滞后与冗余,具体问题:
- 「当前状态」仍写 v1(实际已到 v6)
- 「关键决策」写「点对点直连(无中枢)」,与已实现的 Hub 中转自相矛盾
- Hub 说明重复出现两处;CLI 命令、验证、工程结构之间层级混乱
按读者动线重写(这是什么 → 能做什么 → 怎么用 → 怎么做的 → 深入):
1. 价值主张:突出「能力层」而非「远程控制」的四点差异(结构化/可授权/可审计/可穿透)
2. 能力总览:19 项能力分组表格
3. 快速开始:构建 → Windows 被控端 → Mac 控制端 → MCP 接入
4. 架构:三链路拓扑(直连 / 发现 / Hub)+ 分层职责表
5. 安全模型:认证 → 授权 → 审计 三层收窄 + 零信任启用步骤
6. 命令速查:按「连接设备 / 系统软件 / 图形文件 / 审计密钥」分组
7. MCP 工具表、Hub 中转、开发与三层验证、工程结构、路线图
同步修正:CLI 帮助补充 Hub 参数(--hub-token / --hub-node)
验证:命令与 CLI --help 逐条核对一致;构建 + E2E 21/21 全绿
|
2026-09-27 15:35:54 +08:00 |
|
jkooe
|
3d03945448
|
feat(v6): Hub 中转 —— 跨网段 / 公网接入
新增 apps/hub(中转节点):
- 被控端主动外连注册(/hub/agent),控制端接入配对(/hub/client)
- 配对后双向字节透传 —— Hub 不解析内容、不持有设备密钥
- Hub 令牌鉴权;list 可查在线设备
- 连接语义:控制端断开仅解绑(被控端保持在线);被控端掉线连带关闭控制端
- 同一被控端同一时刻仅服务一个控制端(占用返回 E_NODE_BUSY)
被控端:
- 新增 hub 配置;启用后不监听本地端口,改为主动外连 Hub(穿 NAT)+ 指数退避重连
- 重构抽出 createAgentCore(),监听模式与 Hub 模式共用同一套鉴权/ACL/能力分发
控制端:
- NodeProfile 新增 hub 字段;toWsUrl 自动附 /hub/client 路径
- client 支持 Hub 配对(控制面消息与 RPC 分离)
修复(Hub 场景暴露):
- cmdConnect 漏传 hub 字段,导致跳过配对直接发 RPC
- Hub unpair 过激进:控制端断开时把被控端也踢下线
- 安全:被控端 hello 时重置认证态与授权(Hub 下同一连接被多控制端复用)
验证:本地 E2E 21/21;构建 + 类型检查全绿;冒烟确认 info/exec 穿透 Hub 且多次接入保持在线
|
2026-09-27 15:04:05 +08:00 |
|
jkooe
|
4ff1b4fd90
|
feat(v5): 多设备管理 + 文件传输
方向 1 · 多设备管理:
- 配置模型升级为 nodes{} + current,自动迁移 v1/v2 单设备扁平配置(零破坏)
- 新增 resolveTarget():按名解析生效设备与控制端身份
- CLI: nodes(列表)/ use(切换)/ remove(移除)/ connect --name(命名)
- 全局 --node <设备名> 单次指定目标,前置(--node=x cmd)与后置(cmd --node x)均可
方向 2 · 文件传输(分块 RPC,协议零改动):
- fs.list(递归+glob)/ fs.stat / fs.read(offset+max_bytes 分块)/ fs.write(原子写+append)
- 小文件(<=8MB)首次读取附带 sha256;路径白名单 fs_roots,越界 -> E_ACL_DENIED
- CLI: ls / stat / cat / pull / push(自动分块;pull 与 push 均原子落盘)
- MCP: na_fs_list / na_fs_read / na_fs_write
能力总数 15 -> 19;MCP 工具 12 -> 15
验证:本地 E2E 20/20(新增文件传输全链路用例);构建 + 类型检查全绿;
冒烟确认 3MB 文件 pull 后 sha256 一致、白名单越界被拒
|
2026-09-27 13:25:38 +08:00 |
|
jkooe
|
3d0eb1c696
|
feat(v4): 无感体验 —— 局域网自动发现 + 断线自动重连
自动发现(免手抄 IP):
- 被控端 UDP 心跳广播(默认 5s 一次,目标 255.255.255.255:8766)
- 控制端 Discovery 监听 + TTL 设备表(默认 30s 过期)
- 报文不含任何凭据;可 discovery.enabled:false 关闭
- 控制端取「报文来源 IP」作为可达地址(比被控端自报地址可靠)
- CLI: nodeagent discover [--wait 5];MCP: na_discover
断线自动重连:
- client 新增 autoReconnect(指数退避 1s→30s + ±15% 抖动)
- 重连前清空在途请求(统一 E_NODE_OFFLINE),避免悬挂
- onStateChange 回调(connected/reconnecting/closed)
- close() 会停止重连,不会关不掉
修复:UDP socket 需先 bind 再 setBroadcast(未绑定时报 EBADF)
验证:本地 E2E 19/19(新增发现 + 重连两用例);构建与类型检查全绿
|
2026-09-27 13:11:13 +08:00 |
|
jkooe
|
edc69b0a34
|
feat(v3+): 审计日志 + 调用限速
审计(安全闭环最后一环):
- 被控端将关键动作以 JSONL 写入 <数据目录>/audit.log:agent 启停 / 认证成败 /
invoke 结果 / ACL 拒绝 / 限速拦截
- 大小轮转(默认 10MB × 5 份);参数默认只记 sha256 摘要,log_args 开启后
自动脱敏(pass/token/secret/key/auth 键 → ***,字符串截断 200 字符)
- 审计写入失败被吞掉,绝不阻断业务主流程
- 新增能力 system.audit.list(支持 limit/since/client_id/type 筛选)
- CLI: nodeagent audit;MCP: na_audit
限速:
- 落地 ACL 中预留的 max_calls_per_min(按调用方滑动窗口计数)
- 超限返回 E_RATE_LIMITED(-32407)
验证:本地 E2E 全绿;零信任用例扩展为 6 项断言(授权/拒绝/审计留痕/脱敏/限速/未注册/错钥)
|
2026-09-27 11:56:37 +08:00 |
|
jkooe
|
5b7e967868
|
feat(v3): 零信任安全 —— Ed25519 身份认证 + 能力级 ACL
认证(两模式并存,默认 psk 向后兼容):
- 新增 auth_mode: psk | ed25519
- ed25519:每控制端独立密钥对,挑战-应答签名验证(替代共享密钥)
- 密钥用 Node 内置 crypto 生成(零新依赖),Base64(DER) 单行格式
- 私钥存 <数据目录>/keys/ed25519.json(600 权限,永不外传)
授权(能力级 ACL):
- acl.clients[] 按调用方登记 pubkey + allow/deny(glob 匹配)
- 判定顺序 deny → allow → default_effect(默认拒绝)
- 未注册身份 / 验签失败 → 握手拒绝;未授权能力 → E_ACL_DENIED
- auth_ok 下发 authorized 子集,CLI 以 授权/未授权 标识展示授权矩阵
接入:
- CLI: keygen(生成密钥 + 打印 ACL 配置片段)、connect --auth-mode ed25519
- MCP: 按 auth_mode 自动选择认证方式
- install.ps1: 显式写 auth_mode + 零信任指引
验证:本地 E2E 17/17(新增零信任四项断言);手动端到端复验通过
|
2026-09-27 11:01:58 +08:00 |
|
jkooe
|
792937c6b0
|
feat(v2): 图形接管 —— 屏幕感知 + 输入控制
新增 7 项能力(总计 14):
- screen.info / screen.capture:显示器信息、截屏(region/scale/format)
- input.mouse.move/click/scroll、input.key.type/press:鼠标键盘控制
安全设计:
- input.* 为高危能力,由被控端 allow_input 开关统一管控,默认禁用
- 未开启时返回 E_CAPABILITY_DISABLED(附开启指引)
- 文本输入经 Base64 传参、PowerShell 侧解码,杜绝内容注入
- 按键名走白名单映射(虚拟键码),非法键名直接拒绝
实现:纯 PowerShell(System.Drawing 截屏 + user32.dll SendInput),
无原生编译、无第三方依赖。
接入:
- CLI: screen / screenshot / mouse / key 命令
- MCP: na_screenshot(直接返回图像)/ na_mouse / na_key
- install.ps1: 新增 -AllowInput 开关
- verify.mjs: 新增 v2.1~v2.3 验收项
验证:本地 E2E 16/16;远程验收 12 通过 / 0 失败
|
2026-09-27 03:43:10 +08:00 |
|
jkooe
|
77c024703a
|
feat: nodeagent v1 初期开发完成
- packages/protocol: 协议定义(信封/方法/错误码/能力schema/校验/HMAC/ULID)
- packages/client: 控制端客户端库(连接/握手/invoke/超时)
- apps/agent: Windows 被控端(监听/HMAC认证/能力分发/7项能力/进程执行)
- apps/cli: 控制端 CLI(connect/info/status/ps/services/exec/apps/install/list/invoke)
- apps/mcp: MCP server(na_* 工具,接入 WorkBuddy)
- scripts: install.ps1 / uninstall.ps1(开机自启 + 防火墙 + 密钥生成)
- tests/e2e: 端到端测试 13/13 通过(握手/能力/超时强杀/参数校验/鉴权失败/未认证)
|
2026-09-27 01:06:35 +08:00 |
|