Commit Graph
10 Commits
Author SHA1 Message Date
jkooe cedc46d090 feat(v20): 版本纪律 + 发版自动化(对齐「做好版本功能 + GitHub 同步资产」)
## 一、版本功能(防新旧混用)
1. **单一版本源 + 构建注入**:根 package.json 的 version、git sha、构建时间经 esbuild
   `--define` 注入 agent;`system.info.build` 新增 `version/commit/built_at`(原有 `hash` 指纹不变)。
   开发态用 typeof 探测(未注入也不崩)。
2. **握手携带版本**:`auth_ok` 新增可选字段 `agent_version` / `build` / `protocol`(只增不减 → 旧控制端忽略即可)。
3. **能力级兼容比对**:新增纯函数 `capabilityDiff(local, remote)` ——
   - `missingOnRemote`:本地有远端没有 → **远端较旧**,提示更新被控端
   - `unknownLocally`:远端有本地没有 → **本控制端较旧**(不影响既有功能)
   控制端不比版本号而比**能力集合**:版本号可能相同而内容不同,能力集合不会骗人。
4. **CLI 体检**:`nodeagent info` / `connect` 直接显示被控端版本与能力对齐情况,
   把"调用时才炸"变成一句人话提示。

## 二、发版自动化(GitHub 资产同步)
`pnpm release <x.y.z|patch|minor|major>`:前置检查(干净/在 main/与远端同步)→ 改 7 个 package.json
→ 构建+打包 → 生成资产 → 提交打标签推送 → `gh release create` 上传。
- 资产:`agent.mjs`(**自更新载荷**)、`nodeagent-win-x64.zip`(人工安装包)、
  `latest.json`(version/commit/能力数 + 两个资产的 url 与 sha256)、`SHA256SUMS`
- `--dry-run` 无副作用演练;`--no-publish` 只到本地标签
- 能力数从 dist 动态取(避免写死漂移);刻意排除 `.github/`(缺 workflow 权限推不了)

## 三、兼容性契约文档
新增 `docs/VERSIONING.md`:semver 各位的含义、**只增不改**六条硬规则、
升级顺序建议(**先被控端**:新被控端向后兼容旧 CLI)、两条更新路径、发版流程、排查手册。

## 验证
- 单测 147 → **149**(新增 capabilityDiff 用例:远端过旧 / 本机过旧 / 完全一致 / 真实清单自比无差异)
- e2e 28 全绿;`node scripts/release.mjs 1.0.0 --dry-run` 演练通过且工作区无副作用
2026-10-04 23:54:51 +08:00
jkooe e95a0248da feat(v19): 拉取式自更新 system.agent.update(42 项)—— 回答「能否直接用 GitHub 做更新服务器」
## 结论:能,而且这是「控制端与被控端不可达」场景的正解
`deploy`(推送式)要求两者可达;本能力只要求**被控端能上网**,因此跨网段/NAT/异地都能更新。
GitHub Release / raw / 自建镜像 / 任意 http(s) 地址均可 —— 地址是参数,不写死。

## 实现(apps/agent/src/capabilities/selfupdate.ts)
下载 → **校验 sha256** → 备份 → **原子替换**(同目录 rename)→ 受控重启(复用 v7)→ CLI 复核指纹
- 出口:CLI `nodeagent update --url <u> --sha256 <h> [--dry-run]` · MCP `na_agent_update`
- 审计新增 `agent.update` 事件(记录 url / 前后指纹 / 字节数 / 备份路径)

## 安全底线(否则等于开放远程代码执行)
1. **sha256 必填**,且逐字节校验通过才替换;不符即丢弃并明确报错(未改动任何文件)
2. 只接受 http/https,拒绝 file:// 等其它 scheme
3. 大小上限 64MB + 下载超时(默认 120s)
4. **先备份再原子替换**,失败可回滚(返回 backup_path)
5. `dry_run` 只下载校验、不动文件 —— 用于「先确认能不能更」
6. 不用 fetch 的内置代理(Node 未暴露 undici):国内访问 GitHub 不稳时,
   把 url 指向**自建镜像/加速地址**即可,能力本身接受任意 http(s)

## 真机/本地验证(全程真跑,非纸面)
- e2e 新增:本地 HTTP 服务真跑下载 —— 正确哈希通过 / **错误哈希被拒** / 404 明确报错 /
  非 http(s) scheme 被拒 / 缺 sha256 协议层拒绝 ✓
- 完整流程本地实测:`dry-run 预检` → `真更新`(966KB)→ 备份逐字节一致 → 重启 →
  **复核到新指纹** → 能力 42 项 ✓
- 顺带修:返回值漏 `incoming_hash` 导致 CLI 复核被跳过(真机踩过)
- 单测 126 / e2e 28 全绿

## 已知约束(写进文档)
1. **首次仍要一次性安装**(install.ps1)—— 自更新能力本身得先在机器上,鸡生蛋无解
2. `node.exe`(Node 运行时)不在自更新范围,只换 agent.mjs
2026-10-04 23:03:37 +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 3316f08c92 fix: 修复 Windows 安装后无法启动 —— PowerShell 写入的 JSON 带 UTF-8 BOM
真机报错:启动失败: Unexpected token '', "{"a"... is not valid JSON
根因:Windows PowerShell 5.1 的 Set-Content -Encoding UTF8 会写入 BOM(U+FEFF),
      Node 侧 JSON.parse 拒绝解析带 BOM 的文本。

双管齐下修复:
1. 写端 install.ps1:改用 [System.IO.File]::WriteAllText + UTF8Encoding($false)
   写出无 BOM 的 UTF-8
2. 读端容错(兼容已被写坏的配置):
   - apps/agent/src/config.ts:读配置时剥离开头 BOM
   - packages/client/src/config.ts:同上

验证:构造带 BOM 的 agent.json(ef bb bf 开头),agent 可正常启动;
单元 26/26、E2E 21/21 全绿
2026-09-27 19:32:53 +08:00
jkooe b350a41803 fix(install.ps1): 安装后验证端口监听,并在连接命令中填入真实 IP
真机安装反馈暴露两处缺陷:
1. 只打印计划任务状态(Ready)就宣告完成,未确认端口真的在监听 ——
   用户按提示连接时会超时,却得不到任何线索。
   现改为轮询等待端口进入 Listen(最多 15s),失败时打印任务最后运行结果
   与三步排查命令(手动启动任务 / 查进程 / 前台运行看报错)。
2. 连接提示里的 <THIS-IP> 是字面占位符,用户照抄会失败。
   现改为填入实际探测到的本机 IPv4。
2026-09-27 19:29:56 +08:00
jkooe 192e08b171 feat: Windows 便携安装包构建(免装 Node.js)
新增 pnpm pack:win(scripts/pack.mjs),一键产出 nodeagent-win-x64.zip:
- esbuild 打包被控端为单文件 bundle(含全部依赖,约 800KB)
- 自动下载 Node.js Windows x64 运行时(npmmirror,node.exe)
- 组装便携包并打 zip(node.exe + agent.mjs + install.ps1 + uninstall.ps1)

改造 install.ps1:
- 优先使用包内 node.exe + agent.mjs(便携包模式)
- 否则回退系统 Node.js + 仓库构建产物(开发模式)
- 无 Node.js 的 Windows 机器也能一键安装

配套:
- .gitignore 忽略 release/(产物体积大,不入库)
- README 安装说明改为「安装包(推荐)/ 开发模式」两方式

验证:打包产物 32MB;解压后 agent.mjs 可独立运行(19 项能力、wss 监听);
esbuild bundle 通过 banner 提供 createRequire 兼容 CJS 依赖(node-forge)
2026-09-27 18:03:04 +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 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