fix(v23): 自重启在非管理员身份下的降级 + deploy 备份不再堆积

## ① system.agent.restart / deploy 重启:加权限降级(真机坐实)
原实现硬用 `New-ScheduledTaskPrincipal -RunLevel Highest`(前提是"agent 以管理员运行,
普通权限 taskkill 杀不掉它")。但真机 2026-10-09 坐实:**agent 以普通用户运行时
(is_admin=False),非管理员注册 Highest 任务会被系统拒绝** → deploy/restart 一律报
"注册重启任务失败 exit=1",只有文件更新成功、进程不重启(部署"部分成功"的假象)。

修:两级降级 —— 先试 Highest(管理员场景保持原语义),注册后校验;
失败则不指定 -Principal(默认继承当前权限级别 Limited),同权限下 taskkill 自己完全够用。
已在被控端用 schtasks /RL LIMITED 现场验证过该路径可行。

## ② deploy 备份改为固定名,并清理历史堆积
此前每次部署写 `${target}.bak-<时间戳>`,真机 D:\Nodeagent 下堆了 15+ 个(单文件 1MB)。
部署回滚只需要「上一个可用版本」→ 改为固定名 `${target}.bak`(覆盖式)。
并在上传后 best-effort 清理老格式 `.bak-*`(平台分流:Windows 用 PS,类 Unix 用 rm;
清理失败不影响部署结果,只提示)。

## 验证
单测 250 全绿;e2e 30 全绿;7 包构建通过。
⚠️ ① 在 agent 内,需部署新包才能真机验证;② 在本地 CLI,立即可见。
This commit is contained in:
jkooe committed 2026-10-09 23:44:35 +08:00
1 parent 28d590a4e5
commit 7e63963e4f
2 files changed
+27 -2

No files matched your search

+21 -1
View File
@@ -273,7 +273,10 @@ export async function cmdDeploy(localFile: string, opts: Options): Promise<void>
const uploadInfo = await withClient(async (c) => {
// 备份走协议自带的 fs 能力(而非 shell 的 Copy-Item)——
// Copy-Item 是 Windows 专用,在 macOS 被控端上会静默失败(真机踩过:以为备份了,其实没有)。
const backup = `${target}.bak-${Date.now()}`;
// 备份用**固定名**(覆盖式):此前用 `.bak-<时间戳>`,每部署一次就多一个文件 ——
// 真机 2026-10-09 发现 D:\Nodeagent 下堆了 15+ 个 bak(单文件 1MB,纯浪费)。
// 部署回滚只需要「上一个可用版本」,一份就够,故改为覆盖写。
const backup = `${target}.bak`;
let backupPath = '';
try {
const st = await c.invoke<{ size?: number; exists?: boolean }>(CapabilityNames.FsStat, { path: target });
@@ -329,6 +332,23 @@ export async function cmdDeploy(localFile: string, opts: Options): Promise<void>
offset += part.length;
}
console.log(`✓ 已上传 ${(buf.length / 1024).toFixed(0)} KB`);
// best-effort 清理历史的时间戳备份(老格式 `.bak-<ts>`)。
// 平台分流:Windows 用 PS,类 Unix 用 rm。清不掉不影响部署,只提示。
try {
const isWin = String((info as { os?: string }).os ?? '').toLowerCase().startsWith('win');
const cleanup = isWin
? `Get-ChildItem '${target}.bak-*' -EA SilentlyContinue | Remove-Item -Force -EA SilentlyContinue; (Get-ChildItem '${target}.bak-*' -EA SilentlyContinue | Measure-Object).Count`
: `rm -f '${target}.bak-'* 2>/dev/null; ls '${target}.bak-'* 2>/dev/null | wc -l`;
const r = await c.invoke<{ stdout?: string }>(CapabilityNames.ShellExec, { command: cleanup, timeout_ms: 15_000 });
const left = Number((r.data?.stdout ?? '').trim());
if (r.status === 'ok' && Number.isFinite(left)) {
if (left === 0) console.log('✓ 已清理历史时间戳备份(老格式)');
else console.log(`⚠️ 仍有 ${left} 个历史备份未清理(可手动删除)`);
}
} catch {
/* 清理是附加项,失败不影响部署结果 */
}
return { backupPath };
});