Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b6b063e2b | ||
|
|
cf51e0415a | ||
|
|
c062d1cc8b | ||
|
|
0b858bb343 | ||
|
|
a769479a2a | ||
|
|
5e32d7fa55 | ||
|
|
eebfb45f73 | ||
|
|
419f6dca13 | ||
|
|
1a2d1c7825 | ||
|
|
b6e58dbcc4 | ||
|
|
5bacade667 |
No files matched your search
@@ -352,11 +352,40 @@ jobs:
|
||||
- name: 列出待发布文件(先看清再上传)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "--- dist 实际内容 ---"
|
||||
find dist -type f | sort | head -40
|
||||
echo "--- 安装包 ---"
|
||||
find dist -type f \( -name '*.exe' -o -name '*.msi' \) -printf '%10s %p\n' | sort -k2
|
||||
n=$(find dist -type f \( -name '*.exe' -o -name '*.msi' \) | wc -l)
|
||||
echo "共 $n 个安装包"
|
||||
# 两架构各一套(exe+msi)= 4 个;少一个说明产物不全,宁可红也不要静默少发
|
||||
if [ "$n" -lt 4 ]; then echo "::error::安装包数量不足($n < 4),架构可能缺失"; exit 1; fi
|
||||
|
||||
# 期望值必须与上面的 build 矩阵一致:
|
||||
# x64 → msi + nsis(2 个)
|
||||
# arm64 → 仅 nsis(1 个,WiX 的 arm64 MSI 支持面窄,刻意不出)
|
||||
# 合计 3 个。
|
||||
#
|
||||
# ⚠️ 这里曾写死「两架构各一套(exe+msi)= 4 个」,与矩阵漂移后**每次必红** ——
|
||||
# 红门禁等于没有门禁(本项目反复踩的同一类坑:断言与实现各改各的)。
|
||||
# 故改为**按架构**断言,并在缺失时报出具体是哪个架构,便于一眼定位。
|
||||
fail=0
|
||||
for spec in "x64:2" "arm64:1"; do
|
||||
arch=${spec%%:*}; want=${spec##*:}
|
||||
dir="dist/nodeagent-console-windows-$arch"
|
||||
# ⚠️ 变量引用一律用 ${var} 形式:`$dir)` 这种「$var + 全角括号」在
|
||||
# set -u 下会被 bash 当成变量名的一部分 → "unbound variable",
|
||||
# 而写法在本地肉眼完全正常(本地实测复现过)。
|
||||
if [ ! -d "${dir}" ]; then
|
||||
echo "::error::缺少 ${arch} 的产物目录(${dir})—— 该架构构建失败或 artifact 名称变更"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
got=$(find "${dir}" -type f \( -name '*.exe' -o -name '*.msi' \) | wc -l)
|
||||
echo " ${arch}: ${got} / ${want}"
|
||||
if [ "${got}" -lt "${want}" ]; then
|
||||
echo "::error::${arch} 安装包不足(${got} < ${want})—— 产物缺失,或矩阵已变更但本断言未同步"
|
||||
fail=1
|
||||
fi
|
||||
done
|
||||
[ "${fail}" -eq 0 ] || exit 1
|
||||
echo "✓ 两架构安装包齐全"
|
||||
|
||||
- name: 挂到对应 Release
|
||||
env:
|
||||
|
||||
+56
-1
@@ -7,7 +7,62 @@
|
||||
|
||||
## [未发布]
|
||||
|
||||
> 本段为 **v2.1.0** 定稿段(版本统一见 `efe4744`):selfupdate 代理出网、LKG 内容指针、
|
||||
### 修复 —— 发版脚本在版本号已钉在树中时卡死(`451d44a`)
|
||||
|
||||
`scripts/release.mjs` 无条件执行 `git commit`。当版本号已经作为 `chore(release)`
|
||||
提交进树(v2.1.0 的实际流程)时,`git add -A` 后暂存区为空,`git commit` 以
|
||||
`nothing to commit` 非零退出,整个发版停在最后一步,且报错来自 git 而非发布逻辑
|
||||
(极易误判为工作区问题)。改为:暂存区为空则跳过 commit,标签与 Release 照常创建。
|
||||
|
||||
### 安全 —— 依赖漏洞清零(`pnpm audit --audit-level=high` 由 3 high → 0)
|
||||
|
||||
Quality Gate 的「依赖漏洞扫描(SCA)」在 `451d44a` 上为红,全部来自
|
||||
`@modelcontextprotocol/sdk` 的传递依赖与本仓 devDependency:
|
||||
|
||||
- `zod <4.6.6`(GHSA-mrhx-c7xc-m3w5)→ 根 `pnpm-workspace.yaml` 加 overrides `^4.6.6`;
|
||||
- `body-parser <2.4.0`(GHSA-27r3-jxmh-p828)→ overrides `^2.4.0`;
|
||||
- `vite <8.3.3`(GHSA-587h-7wmj-h5pm)→ 控制台 devDependency `^8.3.5`。
|
||||
|
||||
⚠️ pnpm 12 起 `package.json` 的 `pnpm` 字段不再被读取(设置迁移到
|
||||
`pnpm-workspace.yaml`)—— 写在那里会被**静默忽略**,与「一直红所以等于没有」
|
||||
是同一类失败形态,故覆盖项写在 workspace 文件里并注明原因。
|
||||
|
||||
### 安全 —— 依赖漏洞彻底清零(中低危一并处理)
|
||||
|
||||
在上一节之后复扫仍余 6 条(2 low / 4 moderate),全部经 MCP SDK 传递:
|
||||
|
||||
- `hono <4.13.11`(serveStatic 路径二次解码绕过中间件)→ overrides `^4.13.14`;
|
||||
- `ip-address <=10.7.3`(zone 标识符二次方耗时 DoS)→ overrides `^10.7.5`;
|
||||
- `fast-uri <3.1.9`(scheme 伪造 / host 混淆 / 路径等价 4 条)→ overrides `^3.1.9`。
|
||||
|
||||
三条与 dependabot #3/#6/#7 同源,覆盖后那三个 PR 已无增量(随提交一并关闭)。
|
||||
当前 `pnpm audit` 输出 **No known vulnerabilities found**。
|
||||
|
||||
### 修复 —— 看门狗日志无界增长(常驻被控端,写满磁盘会拖死 agent)
|
||||
|
||||
`startup-guard.log` 一直是 `appendFileSync` 无限追加。看门狗本身常驻被控端,
|
||||
「坏版本 + supervisor 反复重启」时写得很快,磁盘满会连带把 agent 的审计写入拖死。
|
||||
现按 **1MB × 4 份**(当前 + `.1`…`.3`)轮换:超阈值先丢最旧、再逐个后移、当前滚为 `.1`。
|
||||
轮换与写入**双双失败静默** —— 日志问题绝不能反过来拦住被控端启动。
|
||||
判断逻辑放 `startup-guard-core.mjs` 纯函数(`shouldRotate` / `rotationTargets`),
|
||||
并补 3 条单测(阈值边界含 NaN、命名序列、真实滚存三轮)。
|
||||
|
||||
### 修复 —— 控制台 L2 采集参数必须先出结果才出现
|
||||
|
||||
`AuditView.vue` 里「采集窗口 / 条数上限」两个输入框原先在
|
||||
`v-if="l2Rows.length"` 容器内 —— 用户想「先设 72 小时再采集」做不到,只能先按
|
||||
默认值点一次再改。参数与结果无生命周期关系,已拆出容器常显。
|
||||
|
||||
### 修复 —— e2e 连跑偶发失败(固定端口被上一轮残留占用)
|
||||
|
||||
套件有 8 处 `spawn`,各自 `finally` 只发 `kill()`(SIGTERM)就 `process.exit`,
|
||||
被控端可能来不及退出 → 下一轮固定端口仍被占,表现为「连跑第二次偶发失败,重跑又绿」。
|
||||
改为**包一层 spawn 统一登记**子进程(调用点零改动),进程退出时对存活者 `SIGKILL`;
|
||||
单点收口,将来新增 spawn 也不会漏。实测连跑两次 34/34、退出后无残留 agent 进程。
|
||||
|
||||
## [2.1.0] - 2026-10-26
|
||||
|
||||
> 本段为 **v2.1.0** 定稿段(版本统一见 `a75c5c9`):selfupdate 代理出网、LKG 内容指针、
|
||||
> 三个架构审查 P0 修复、L2 三端暴露,以及 rollback / 看门狗 / na-gui 清理 / 收口。
|
||||
|
||||
### 新增 —— 控制端 `nodeagent rollback`:从 LKG 回滚被控端(ARCH T03 / PRD P0-2)
|
||||
|
||||
@@ -168,7 +168,7 @@ nodeagent --node win audit anchor --note "每日例行" # 追加一个锚点
|
||||
> 真正发挥价值的前提:把锚点文件指向**另一台机器 / 网盘同步目录**。
|
||||
> 本机文件被整盘重写时,锚点也随之消失 —— 那就等于没锚。
|
||||
|
||||
**52 项能力** · **42 个 MCP 工具** · **477 项单元测试** · **50 项端到端用例**(34 通用 + 16 Windows 专属) · **23 项 Rust 壳单测**(真跑 Node sidecar)(CI 在真实 Windows / Linux runner 上验证)
|
||||
**52 项能力** · **42 个 MCP 工具** · **483 项单元测试** · **50 项端到端用例**(34 通用 + 16 Windows 专属) · **23 项 Rust 壳单测**(真跑 Node sidecar)(CI 在真实 Windows / Linux runner 上验证)
|
||||
|
||||
> 关键里程碑:**GUI 语义**(`window.list` + `screen.find`,UIA 找不到自动降级 OCR)
|
||||
> 让 AI 从「看得到画面但读不懂界面」变成「按名字取坐标点下去」。
|
||||
|
||||
@@ -102,6 +102,12 @@ export function describeNetError(err: unknown, timeoutMs: number): string {
|
||||
if (code === 'ENOTFOUND' || code === 'EAI_AGAIN' || code === 'ECONNREFUSED') {
|
||||
return `${msg}(域名解析失败或目标拒绝连接;若配了代理,请核对代理地址与端口)`;
|
||||
}
|
||||
// 2026-10-27 真机补:境内直连 GitHub 的**最常见**失败形态就是 TCP 层 ETIMEDOUT
|
||||
// (不是我们自己的 timeoutMs,也不是 ECONNRESET)。原先它落到下面兜底分支,
|
||||
// 用户只看到一串 IP:443 超时,不知道该干什么 —— 而这时唯一有效的动作就是配代理。
|
||||
if (code === 'ETIMEDOUT' || code === 'EHOSTUNREACH' || code === 'ENETUNREACH') {
|
||||
return `${msg}(连接超时/网络不可达;若目标在境外或需要代理,请设置 NA_PROXY=<代理地址> 或配置系统代理后重试)`;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@vitejs/plugin-vue": "^6.0.7",
|
||||
"typescript": "~6.0.3",
|
||||
"vite": "^8.0.16",
|
||||
"vite": "^8.3.5",
|
||||
"vue-tsc": "^3.3.5"
|
||||
}
|
||||
}
|
||||
@@ -297,27 +297,31 @@ onMounted(() => {
|
||||
本地副本防篡改价值有限,真正的独立性依赖把记录<strong>转发出机</strong>。
|
||||
</n-alert>
|
||||
|
||||
<!-- 采集参数始终可见:早前它在 `v-if="l2Rows.length"` 里面,
|
||||
必须先出一次结果才出现输入框 —— 用户想「先设窗口 72h 再采集」做不到,
|
||||
只能先点一次默认参数再改。参数与结果的生命周期无关,故拆开。 -->
|
||||
<n-space align="center" style="margin-bottom: 8px">
|
||||
<n-text depth="3" style="font-size: 12px">采集窗口(小时)</n-text>
|
||||
<n-input-number
|
||||
v-model:value="l2SinceHours"
|
||||
:min="1"
|
||||
:max="720"
|
||||
:step="1"
|
||||
size="small"
|
||||
style="width: 110px"
|
||||
/>
|
||||
<n-text depth="3" style="font-size: 12px">条数上限</n-text>
|
||||
<n-input-number
|
||||
v-model:value="l2Limit"
|
||||
:min="1"
|
||||
:max="5000"
|
||||
:step="100"
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
/>
|
||||
</n-space>
|
||||
|
||||
<n-space v-if="l2Rows.length" vertical size="small">
|
||||
<n-space align="center">
|
||||
<n-text depth="3" style="font-size: 12px">采集窗口(小时)</n-text>
|
||||
<n-input-number
|
||||
v-model:value="l2SinceHours"
|
||||
:min="1"
|
||||
:max="720"
|
||||
:step="1"
|
||||
size="small"
|
||||
style="width: 110px"
|
||||
/>
|
||||
<n-text depth="3" style="font-size: 12px">条数上限</n-text>
|
||||
<n-input-number
|
||||
v-model:value="l2Limit"
|
||||
:min="1"
|
||||
:max="5000"
|
||||
:step="100"
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
/>
|
||||
</n-space>
|
||||
<n-descriptions :column="2" size="small" label-placement="left" bordered>
|
||||
<n-descriptions-item v-for="row in l2Rows" :key="row.label" :label="row.label">
|
||||
{{ row.text }}
|
||||
|
||||
+3
-3
@@ -457,15 +457,15 @@ node scripts/verify.mjs --host <地址> --key <密钥> --report <报告.md>
|
||||
|
||||
| 项 | 状态 | 落点 |
|
||||
|---|---|---|
|
||||
| 版本统一 v2.1.0 + CHANGELOG 骨架 | ✅ | `efe4744` |
|
||||
| 版本统一 v2.1.0 + CHANGELOG 骨架 | ✅ | `a75c5c9` |
|
||||
| selfupdate 代理出网(NA_PROXY→env→系统代理) | ✅ | `apps/agent/src/net/proxy.ts` |
|
||||
| LKG 内容指针(`hash_full` / `backup_glob`) | ✅ | `apps/agent/src/lkg.ts` |
|
||||
| 控制端 rollback(ARCH T03) | ✅ | `apps/cli/src/cmd/rollback.ts` |
|
||||
| 看门狗启动自动恢复(决策 R-1) | ✅ | `scripts/startup-guard.mjs` + 三端 supervisor 接入 |
|
||||
| L2 三端暴露(MCP `na_audit_l2` + 控制台 + `agent.l2`) | ✅ | `b09ca68` |
|
||||
| L2 三端暴露(MCP `na_audit_l2` + 控制台 + `agent.l2`) | ✅ | `5a2c5f9` |
|
||||
| na-gui 陈旧计划任务白名单清理 | ✅ | `scripts/lib/scheduled-tasks.mjs` + `control.ps1 cleanup` |
|
||||
| L2 e2e + 文档数字守卫 | ✅ | `tests/e2e/*`、`tests/unit/docs-numbers.test.mjs` |
|
||||
| 架构审查三 P0(validate 原型链 / 限速桶 key / describeArgs) | ✅ | `e864486`、`d106214` |
|
||||
| 架构审查三 P0(validate 原型链 / 限速桶 key / describeArgs) | ✅ | `68ea3cd`、`560b3c4` |
|
||||
|
||||
### 遗留(P2 登记,明确不塞进 v2.1.0)
|
||||
|
||||
|
||||
Generated
+250
-50
@@ -4,6 +4,13 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
zod: ^4.6.6
|
||||
body-parser: ^2.4.0
|
||||
hono: ^4.13.14
|
||||
ip-address: ^10.7.5
|
||||
fast-uri: ^3.1.9
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -71,20 +78,20 @@ importers:
|
||||
version: 3.5.43(typescript@6.0.3)
|
||||
vue-router:
|
||||
specifier: ^5.3.1
|
||||
version: 5.3.1(@vue/compiler-sfc@3.5.43)(esbuild@0.28.2)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.43(typescript@6.0.3)))(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3))
|
||||
version: 5.3.1(@vue/compiler-sfc@3.5.43)(esbuild@0.28.2)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.43(typescript@6.0.3)))(rolldown@1.2.12)(vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3))
|
||||
devDependencies:
|
||||
'@tauri-apps/cli':
|
||||
specifier: ^2
|
||||
version: 2.12.1
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^6.0.7
|
||||
version: 6.0.9(vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3))
|
||||
version: 6.0.9(vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3))
|
||||
typescript:
|
||||
specifier: ~6.0.3
|
||||
version: 6.0.3
|
||||
vite:
|
||||
specifier: ^8.0.16
|
||||
version: 8.3.2(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
specifier: ^8.3.5
|
||||
version: 8.3.5(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
vue-tsc:
|
||||
specifier: ^3.3.5
|
||||
version: 3.3.12(typescript@6.0.3)
|
||||
@@ -106,7 +113,7 @@ importers:
|
||||
dependencies:
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: ^1.32.1
|
||||
version: 1.32.1(zod@4.6.5)
|
||||
version: 1.32.1(zod@4.6.7)
|
||||
'@nodeagent/client':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/client
|
||||
@@ -321,7 +328,7 @@ packages:
|
||||
resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==}
|
||||
engines: {node: '>=20'}
|
||||
peerDependencies:
|
||||
hono: ^4
|
||||
hono: ^4.13.14
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||
@@ -347,7 +354,7 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@cfworker/json-schema': ^4.1.1
|
||||
zod: ^3.25 || ^4.0
|
||||
zod: ^4.6.6
|
||||
peerDependenciesMeta:
|
||||
'@cfworker/json-schema':
|
||||
optional: true
|
||||
@@ -359,6 +366,9 @@ packages:
|
||||
'@oxc-project/types@0.152.0':
|
||||
resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==}
|
||||
|
||||
'@oxc-project/types@0.155.0':
|
||||
resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==}
|
||||
|
||||
'@peculiar/asn1-cms@2.11.0':
|
||||
resolution: {integrity: sha512-SlAiDoT/Cd8qaNmbTt78gqyaEvu2fQd6ML6KWJkdjXGrgDKnHHrusVkfQUelkfinL2p665IIADb0JBixtT8W1g==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -412,36 +422,72 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm-eabi@1.2.15':
|
||||
resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.12':
|
||||
resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.15':
|
||||
resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.12':
|
||||
resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.15':
|
||||
resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.12':
|
||||
resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.15':
|
||||
resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.12':
|
||||
resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.15':
|
||||
resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.12':
|
||||
resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.15':
|
||||
resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.12':
|
||||
resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -449,6 +495,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.15':
|
||||
resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.12':
|
||||
resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -456,6 +509,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.15':
|
||||
resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.12':
|
||||
resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -463,6 +523,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.15':
|
||||
resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.12':
|
||||
resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -470,6 +537,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.15':
|
||||
resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.12':
|
||||
resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -477,6 +551,13 @@ packages:
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.15':
|
||||
resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.12':
|
||||
resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -484,24 +565,49 @@ packages:
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.15':
|
||||
resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.12':
|
||||
resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.15':
|
||||
resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.12':
|
||||
resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.15':
|
||||
resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.12':
|
||||
resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.15':
|
||||
resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rolldown/pluginutils@1.0.1':
|
||||
resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
|
||||
|
||||
@@ -709,8 +815,8 @@ packages:
|
||||
birpc@2.9.0:
|
||||
resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==}
|
||||
|
||||
body-parser@2.3.0:
|
||||
resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==}
|
||||
body-parser@2.4.0:
|
||||
resolution: {integrity: sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
bytes@3.1.2:
|
||||
@@ -876,8 +982,8 @@ packages:
|
||||
fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
fast-uri@3.1.8:
|
||||
resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==}
|
||||
fast-uri@3.1.9:
|
||||
resolution: {integrity: sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==}
|
||||
|
||||
fdir@6.5.0:
|
||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||
@@ -932,8 +1038,8 @@ packages:
|
||||
resolution: {integrity: sha512-nbfWpyRMcMrPMmDwJB+dhX/eiaPKtc2RB+0QZskqJ3WjRA/FDS0e9hZrx8EC/lbEv8gXy98FcDbNa/dspAaJMg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
hono@4.13.9:
|
||||
resolution: {integrity: sha512-7dMkQmZoC4E6F7AtaQSPhlWAdnBti+j7rreMZl8QB4jFiEhP9TWbGWUMi8WYzBCgmgulxuvLQupKqo+Co6Omyg==}
|
||||
hono@4.13.14:
|
||||
resolution: {integrity: sha512-yhRLQ21U6qa9Hsu2N7Qcbh8tE+WKEcoErjIo56LeSGiGXGp9sA7UpE86Ui9uexb61KakiGwuHMn2QdV7w6i6kQ==}
|
||||
engines: {node: '>=16.9.0'}
|
||||
|
||||
hookable@5.5.3:
|
||||
@@ -950,8 +1056,8 @@ packages:
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
ip-address@10.7.2:
|
||||
resolution: {integrity: sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==}
|
||||
ip-address@10.7.5:
|
||||
resolution: {integrity: sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
@@ -1181,6 +1287,10 @@ packages:
|
||||
resolution: {integrity: sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postcss@8.5.31:
|
||||
resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
proxy-addr@2.0.8:
|
||||
resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==}
|
||||
engines: {node: '>= 0.10'}
|
||||
@@ -1196,6 +1306,10 @@ packages:
|
||||
resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
qs@6.16.1:
|
||||
resolution: {integrity: sha512-5Px6J7rfHBAGUhNQ3es4YzcOdBBw0SDcVtThJml4RdnKw4tKs2epA0kPZ+K8X+WiHktT93RHVcQ/3ym5aTCgtg==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
quansync@0.2.11:
|
||||
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
|
||||
|
||||
@@ -1223,6 +1337,11 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
rolldown@1.2.15:
|
||||
resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
|
||||
router@2.2.0:
|
||||
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
|
||||
engines: {node: '>= 18'}
|
||||
@@ -1380,13 +1499,13 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.0.11
|
||||
|
||||
vite@8.3.2:
|
||||
resolution: {integrity: sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==}
|
||||
vite@8.3.5:
|
||||
resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^20.19.0 || >=22.12.0
|
||||
'@vitejs/devtools': ^0.7.1
|
||||
'@vitejs/devtools': ^0.7.1 || ^0.8.0
|
||||
esbuild: ^0.27.0 || ^0.28.0
|
||||
jiti: '>=1.21.0'
|
||||
less: ^4.0.0
|
||||
@@ -1494,10 +1613,10 @@ packages:
|
||||
zod-to-json-schema@3.25.2:
|
||||
resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==}
|
||||
peerDependencies:
|
||||
zod: ^3.25.28 || ^4
|
||||
zod: ^4.6.6
|
||||
|
||||
zod@4.6.5:
|
||||
resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==}
|
||||
zod@4.6.7:
|
||||
resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==}
|
||||
|
||||
zrender@6.1.0:
|
||||
resolution: {integrity: sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==}
|
||||
@@ -1605,9 +1724,9 @@ snapshots:
|
||||
'@esbuild/win32-x64@0.28.2':
|
||||
optional: true
|
||||
|
||||
'@hono/node-server@2.1.1(hono@4.13.9)':
|
||||
'@hono/node-server@2.1.1(hono@4.13.14)':
|
||||
dependencies:
|
||||
hono: 4.13.9
|
||||
hono: 4.13.14
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
dependencies:
|
||||
@@ -1630,9 +1749,9 @@ snapshots:
|
||||
|
||||
'@juggle/resize-observer@3.4.0': {}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.32.1(zod@4.6.5)':
|
||||
'@modelcontextprotocol/sdk@1.32.1(zod@4.6.7)':
|
||||
dependencies:
|
||||
'@hono/node-server': 2.1.1(hono@4.13.9)
|
||||
'@hono/node-server': 2.1.1(hono@4.13.14)
|
||||
ajv: 8.20.0
|
||||
ajv-formats: 3.0.1(ajv@8.20.0)
|
||||
content-type: 1.0.5
|
||||
@@ -1642,19 +1761,22 @@ snapshots:
|
||||
eventsource-parser: 3.1.1
|
||||
express: 5.2.1
|
||||
express-rate-limit: 8.7.0(express@5.2.1)
|
||||
hono: 4.13.9
|
||||
hono: 4.13.14
|
||||
jose: 6.2.12
|
||||
json-schema-typed: 8.0.2
|
||||
pkce-challenge: 5.0.1
|
||||
raw-body: 3.0.2
|
||||
zod: 4.6.5
|
||||
zod-to-json-schema: 3.25.2(zod@4.6.5)
|
||||
zod: 4.6.7
|
||||
zod-to-json-schema: 3.25.2(zod@4.6.7)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@noble/hashes@1.8.0': {}
|
||||
|
||||
'@oxc-project/types@0.152.0': {}
|
||||
'@oxc-project/types@0.152.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-project/types@0.155.0': {}
|
||||
|
||||
'@peculiar/asn1-cms@2.11.0':
|
||||
dependencies:
|
||||
@@ -1753,48 +1875,93 @@ snapshots:
|
||||
'@rolldown/binding-android-arm-eabi@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm-eabi@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-android-arm64@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-arm64@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-darwin-x64@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-freebsd-x64@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm-gnueabihf@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-gnu@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-arm64-msvc@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.12':
|
||||
optional: true
|
||||
|
||||
'@rolldown/binding-win32-x64-msvc@1.2.15':
|
||||
optional: true
|
||||
|
||||
'@rolldown/pluginutils@1.0.1': {}
|
||||
|
||||
'@tauri-apps/api@2.12.1': {}
|
||||
@@ -1864,10 +2031,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/node': 22.20.4
|
||||
|
||||
'@vitejs/plugin-vue@6.0.9(vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3))':
|
||||
'@vitejs/plugin-vue@6.0.9(vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3))':
|
||||
dependencies:
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
vite: 8.3.2(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
vite: 8.3.5(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
vue: 3.5.43(typescript@6.0.3)
|
||||
|
||||
'@volar/language-core@2.4.28':
|
||||
@@ -1985,7 +2152,7 @@ snapshots:
|
||||
ajv@8.20.0:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-uri: 3.1.8
|
||||
fast-uri: 3.1.9
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
@@ -2012,7 +2179,7 @@ snapshots:
|
||||
|
||||
birpc@2.9.0: {}
|
||||
|
||||
body-parser@2.3.0:
|
||||
body-parser@2.4.0:
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
content-type: 2.1.0
|
||||
@@ -2020,7 +2187,7 @@ snapshots:
|
||||
http-errors: 2.0.1
|
||||
iconv-lite: 0.7.3
|
||||
on-finished: 2.4.1
|
||||
qs: 6.16.0
|
||||
qs: 6.16.1
|
||||
raw-body: 3.0.2
|
||||
type-is: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
@@ -2166,14 +2333,14 @@ snapshots:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
express: 5.2.1
|
||||
ip-address: 10.7.2
|
||||
ip-address: 10.7.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
express@5.2.1:
|
||||
dependencies:
|
||||
accepts: 2.0.0
|
||||
body-parser: 2.3.0
|
||||
body-parser: 2.4.0
|
||||
content-disposition: 1.1.0
|
||||
content-type: 1.0.5
|
||||
cookie: 0.7.2
|
||||
@@ -2207,7 +2374,7 @@ snapshots:
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
|
||||
fast-uri@3.1.8: {}
|
||||
fast-uri@3.1.9: {}
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.7):
|
||||
optionalDependencies:
|
||||
@@ -2261,7 +2428,7 @@ snapshots:
|
||||
|
||||
highlight.js@11.12.0: {}
|
||||
|
||||
hono@4.13.9: {}
|
||||
hono@4.13.14: {}
|
||||
|
||||
hookable@5.5.3: {}
|
||||
|
||||
@@ -2279,7 +2446,7 @@ snapshots:
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
ip-address@10.7.2: {}
|
||||
ip-address@10.7.5: {}
|
||||
|
||||
ipaddr.js@1.9.1: {}
|
||||
|
||||
@@ -2478,6 +2645,12 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.2
|
||||
|
||||
postcss@8.5.31:
|
||||
dependencies:
|
||||
nanoid: 3.3.20
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.2
|
||||
|
||||
proxy-addr@2.0.8:
|
||||
dependencies:
|
||||
forwarded: 0.2.0
|
||||
@@ -2494,6 +2667,11 @@ snapshots:
|
||||
es-define-property: 1.0.1
|
||||
side-channel: 1.1.1
|
||||
|
||||
qs@6.16.1:
|
||||
dependencies:
|
||||
es-define-property: 1.0.1
|
||||
side-channel: 1.1.1
|
||||
|
||||
quansync@0.2.11: {}
|
||||
|
||||
range-parser@1.3.0: {}
|
||||
@@ -2531,6 +2709,28 @@ snapshots:
|
||||
'@rolldown/binding-openharmony-arm64': 1.2.12
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.2.12
|
||||
'@rolldown/binding-win32-x64-msvc': 1.2.12
|
||||
optional: true
|
||||
|
||||
rolldown@1.2.15:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.155.0
|
||||
'@rolldown/pluginutils': 1.0.1
|
||||
optionalDependencies:
|
||||
'@rolldown/binding-android-arm-eabi': 1.2.15
|
||||
'@rolldown/binding-android-arm64': 1.2.15
|
||||
'@rolldown/binding-darwin-arm64': 1.2.15
|
||||
'@rolldown/binding-darwin-x64': 1.2.15
|
||||
'@rolldown/binding-freebsd-x64': 1.2.15
|
||||
'@rolldown/binding-linux-arm-gnueabihf': 1.2.15
|
||||
'@rolldown/binding-linux-arm64-gnu': 1.2.15
|
||||
'@rolldown/binding-linux-arm64-musl': 1.2.15
|
||||
'@rolldown/binding-linux-ppc64-gnu': 1.2.15
|
||||
'@rolldown/binding-linux-s390x-gnu': 1.2.15
|
||||
'@rolldown/binding-linux-x64-gnu': 1.2.15
|
||||
'@rolldown/binding-linux-x64-musl': 1.2.15
|
||||
'@rolldown/binding-openharmony-arm64': 1.2.15
|
||||
'@rolldown/binding-win32-arm64-msvc': 1.2.15
|
||||
'@rolldown/binding-win32-x64-msvc': 1.2.15
|
||||
|
||||
router@2.2.0:
|
||||
dependencies:
|
||||
@@ -2658,7 +2858,7 @@ snapshots:
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.7
|
||||
|
||||
unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2)):
|
||||
unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2)):
|
||||
dependencies:
|
||||
'@jridgewell/remapping': 2.3.5
|
||||
picomatch: 4.0.7
|
||||
@@ -2666,7 +2866,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
esbuild: 0.28.2
|
||||
rolldown: 1.2.12
|
||||
vite: 8.3.2(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
vite: 8.3.5(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
|
||||
vary@1.1.2: {}
|
||||
|
||||
@@ -2675,12 +2875,12 @@ snapshots:
|
||||
evtd: 0.2.4
|
||||
vue: 3.5.43(typescript@6.0.3)
|
||||
|
||||
vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2):
|
||||
vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2):
|
||||
dependencies:
|
||||
lightningcss: 1.33.0
|
||||
picomatch: 4.0.7
|
||||
postcss: 8.5.29
|
||||
rolldown: 1.2.12
|
||||
postcss: 8.5.31
|
||||
rolldown: 1.2.15
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 22.20.4
|
||||
@@ -2694,7 +2894,7 @@ snapshots:
|
||||
|
||||
vscode-uri@3.2.0: {}
|
||||
|
||||
vue-router@5.3.1(@vue/compiler-sfc@3.5.43)(esbuild@0.28.2)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.43(typescript@6.0.3)))(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3)):
|
||||
vue-router@5.3.1(@vue/compiler-sfc@3.5.43)(esbuild@0.28.2)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.43(typescript@6.0.3)))(rolldown@1.2.12)(vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2))(vue@3.5.43(typescript@6.0.3)):
|
||||
dependencies:
|
||||
'@vue-macros/common': 3.1.4(vue@3.5.43(typescript@6.0.3))
|
||||
'@vue/devtools-api': 8.2.1
|
||||
@@ -2710,13 +2910,13 @@ snapshots:
|
||||
picomatch: 4.0.7
|
||||
scule: 1.3.0
|
||||
tinyglobby: 0.2.17
|
||||
unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.4)(esbuild@0.28.2))
|
||||
unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.5(@types/node@22.20.4)(esbuild@0.28.2))
|
||||
unplugin-utils: 0.3.2
|
||||
vue: 3.5.43(typescript@6.0.3)
|
||||
optionalDependencies:
|
||||
'@vue/compiler-sfc': 3.5.43
|
||||
pinia: 4.0.3(@vue/devtools-api@8.2.1)(typescript@6.0.3)(vue@3.5.43(typescript@6.0.3))
|
||||
vite: 8.3.2(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
vite: 8.3.5(@types/node@22.20.4)(esbuild@0.28.2)
|
||||
transitivePeerDependencies:
|
||||
- '@farmfe/core'
|
||||
- '@rsbuild/core'
|
||||
@@ -2765,11 +2965,11 @@ snapshots:
|
||||
|
||||
ws@8.21.3: {}
|
||||
|
||||
zod-to-json-schema@3.25.2(zod@4.6.5):
|
||||
zod-to-json-schema@3.25.2(zod@4.6.7):
|
||||
dependencies:
|
||||
zod: 4.6.5
|
||||
zod: 4.6.7
|
||||
|
||||
zod@4.6.5: {}
|
||||
zod@4.6.7: {}
|
||||
|
||||
zrender@6.1.0:
|
||||
dependencies:
|
||||
|
||||
@@ -3,3 +3,21 @@ packages:
|
||||
- 'apps/*'
|
||||
allowBuilds:
|
||||
esbuild: true
|
||||
|
||||
# 依赖漏洞门禁(Quality Gate 的 pnpm audit --audit-level=high)用的显式覆盖。
|
||||
#
|
||||
# 为什么必须钉:`@modelcontextprotocol/sdk` 的传递依赖落后于安全版本,
|
||||
# 审计会稳定报 3 个 high(zod <4.6.6、body-parser <2.4.0),而它们都不由
|
||||
# 本仓直接控制 —— 不覆盖就永远是红门禁(等于没有门禁)。
|
||||
# 均为同 major 的 patch 级抬升,语义风险低;升级 SDK 时若已自带修复版,可移除。
|
||||
#
|
||||
# ⚠️ pnpm 12 起 `package.json` 的 `pnpm` 字段不再被读取(设置迁移到本文件),
|
||||
# 写在那里会被静默忽略 —— 与「一直红所以等于没有」是同一类失败形态。
|
||||
overrides:
|
||||
zod: ^4.6.6
|
||||
body-parser: ^2.4.0
|
||||
# 2026-10-27:MCP SDK 传递链的剩余中低危,一并抬到修复版(同 major)。
|
||||
# 对应 dependabot #3/#6/#7,覆盖后那三个 PR 已无增量,随同一提交关停。
|
||||
hono: ^4.13.14
|
||||
ip-address: ^10.7.5
|
||||
fast-uri: ^3.1.9
|
||||
@@ -18,6 +18,26 @@
|
||||
/** nodeagent 自己注册过的计划任务名(含历史遗留)。只增不改。 */
|
||||
export const TASK_WHITELIST = ['nodeagent', 'na-gui', 'nodeagent-console'];
|
||||
|
||||
/**
|
||||
* 自重启任务前缀 —— `system.agent.restart` 每次重启都注册
|
||||
* `nodeagent-selfrestart-<毫秒时间戳>`(动作是「杀旧 PID → 前台拉起新进程」)。
|
||||
*
|
||||
* 2026-10-27 真机发现:这类任务不在上面的白名单里,于是**卸载时漏删**——
|
||||
* 留下的任务会继续尝试拉起已被删除的 agent.mjs,形成每次登录都失败一次的僵尸。
|
||||
* 但它也不能被当成垃圾随手清:**正在 Running 的那一个往往就是当前 agent 的
|
||||
* 父任务**(删除会连带杀掉 agent)。故只把它纳入「卸载清理」的判定集合,
|
||||
* 由调用方在「已经停掉 agent」之后使用。
|
||||
*/
|
||||
export const SELF_RESTART_PREFIX = 'nodeagent-selfrestart-';
|
||||
|
||||
/** `nodeagent-selfrestart-<纯数字>` —— 严格到毫秒时间戳形态,不接受任何通配。 */
|
||||
const SELF_RESTART_RE = /^nodeagent-selfrestart-\d{6,}$/;
|
||||
|
||||
/** 是否是本框架的自重启任务(严格命名空间,非模糊匹配)。 */
|
||||
export function isSelfRestartTask(name) {
|
||||
return typeof name === 'string' && SELF_RESTART_RE.test(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划删除名单:白名单内**且实际存在**的任务,按白名单固定顺序返回。
|
||||
*
|
||||
@@ -37,5 +57,11 @@ export function planTaskCleanup(existing) {
|
||||
for (const name of TASK_WHITELIST) {
|
||||
if (present.has(name)) out.push(name);
|
||||
}
|
||||
// 自重启任务:仅接受严格命名空间(`nodeagent-selfrestart-<数字>`),
|
||||
// 按名字排序保证输出稳定;与白名单重名时去重(实际不会发生,防御性)。
|
||||
const selfRestart = [...present].filter(isSelfRestartTask).sort();
|
||||
for (const name of selfRestart) {
|
||||
if (!out.includes(name)) out.push(name);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -31,6 +31,31 @@
|
||||
*/
|
||||
export const STARTUP_GRACE_MS = 30_000;
|
||||
|
||||
/**
|
||||
* 看门狗日志轮换阈值(字节):超过即滚存一份。
|
||||
*
|
||||
* 为什么需要:日志是 `appendFileSync` 无界追加的 —— 每次启动失败/恢复各写一行,
|
||||
* 长期运行(尤其「坏版本 + supervisor 反复重启」)会把磁盘写满,而看门狗自己
|
||||
* 就常驻在这台机器上,磁盘满会连带把 agent 的审计写入一起拖死。
|
||||
* 1MB × 4 份(当前 + 3 份历史)≈ 4MB 上限,对排障足够(最近几百次启动)。
|
||||
*/
|
||||
export const LOG_MAX_BYTES = 1_048_576;
|
||||
|
||||
/** 保留的历史份数(`.1` 最新 … `.N` 最旧)。 */
|
||||
export const LOG_KEEP = 3;
|
||||
|
||||
/** 是否需要轮换(纯函数):严格大于阈值才轮换,避免恰好等于阈值时抖动着反复滚。 */
|
||||
export function shouldRotate(sizeBytes, maxBytes = LOG_MAX_BYTES) {
|
||||
return Number.isFinite(sizeBytes) && sizeBytes > maxBytes;
|
||||
}
|
||||
|
||||
/** 轮换目标文件名(从新到旧):`<log>.1` … `<log>.N`。 */
|
||||
export function rotationTargets(logPath, keep = LOG_KEEP) {
|
||||
const out = [];
|
||||
for (let i = 1; i <= keep; i += 1) out.push(`${logPath}.${i}`);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 全新状态(文件缺失时的起点)。 */
|
||||
export function initialState(nowIso = '') {
|
||||
return { failures: 0, updated_at: nowIso };
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import { spawn } from 'node:child_process';
|
||||
import {
|
||||
closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, readSync, statSync, writeFileSync,
|
||||
closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, readSync, renameSync, statSync,
|
||||
unlinkSync, writeFileSync,
|
||||
} from 'node:fs';
|
||||
import { basename, join, resolve } from 'node:path';
|
||||
import net from 'node:net';
|
||||
@@ -46,6 +47,8 @@ import {
|
||||
initialState,
|
||||
planRestore,
|
||||
readState,
|
||||
rotationTargets,
|
||||
shouldRotate,
|
||||
zeroFailures,
|
||||
} from './lib/startup-guard-core.mjs';
|
||||
|
||||
@@ -81,12 +84,32 @@ export function writeState(dataDir, state) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 追加一行 JSONL 日志:<data-dir>/logs/startup-guard.log(失败静默——日志不拦路)。 */
|
||||
export function appendGuardLog(dataDir, obj) {
|
||||
/**
|
||||
* 追加一行 JSONL 日志:<data-dir>/logs/startup-guard.log(失败静默——日志不拦路)。
|
||||
*
|
||||
* 超过 LOG_MAX_BYTES 时滚存:`.log.1`(次新)… `.log.N`(最旧),`N = LOG_KEEP`。
|
||||
* 轮换本身也**失败静默**:日志出问题绝不能反过来拦住被控端启动。
|
||||
*/
|
||||
export function appendGuardLog(dataDir, obj, opts = {}) {
|
||||
try {
|
||||
mkdirSync(join(dataDir, 'logs'), { recursive: true });
|
||||
const logPath = join(dataDir, 'logs', 'startup-guard.log');
|
||||
try {
|
||||
const size = existsSync(logPath) ? statSync(logPath).size : 0;
|
||||
if (shouldRotate(size, opts.maxBytes)) {
|
||||
const targets = rotationTargets(logPath, opts.keep);
|
||||
const oldest = targets[targets.length - 1];
|
||||
if (existsSync(oldest)) unlinkSync(oldest);
|
||||
for (let i = targets.length - 1; i > 0; i -= 1) {
|
||||
if (existsSync(targets[i - 1])) renameSync(targets[i - 1], targets[i]);
|
||||
}
|
||||
renameSync(logPath, targets[0]);
|
||||
}
|
||||
} catch {
|
||||
/* 轮换失败不影响写入 */
|
||||
}
|
||||
const line = `${JSON.stringify({ ts: new Date().toISOString(), ...obj })}\n`;
|
||||
writeFileSync(join(dataDir, 'logs', 'startup-guard.log'), line, { flag: 'a' });
|
||||
writeFileSync(logPath, line, { flag: 'a' });
|
||||
} catch {
|
||||
/* 日志失败不影响启动 */
|
||||
}
|
||||
|
||||
+29
-1
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* 运行:node tests/e2e/run.mjs
|
||||
*/
|
||||
import { spawn } from 'node:child_process';
|
||||
import { spawn as rawSpawn } from 'node:child_process';
|
||||
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { createRequire } from 'node:module';
|
||||
@@ -25,6 +25,34 @@ const RawWebSocket = requireFromClient('ws');
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = join(__dirname, '../..');
|
||||
|
||||
/**
|
||||
* 子进程登记表 + 兜底清理。
|
||||
*
|
||||
* 为什么需要:本套件有 8 处 spawn(主 agent / TLS / ed25519 / hub / fs / monitor…),
|
||||
* 各自的 finally 只做 `child.kill()`(SIGTERM),随后立刻 process.exit —— 被控端
|
||||
* 可能还没来得及退出就被父进程带走,**下一轮连跑时固定端口仍被占用**,表现为
|
||||
* 「连跑第二次偶发失败」(历史真机现象,重跑又绿,最难查)。
|
||||
*
|
||||
* 做法:包一层 spawn,把所有子进程登记下来;进程退出时统一 SIGKILL。
|
||||
* 调用点无需改动(同名函数遮蔽),单点收口也不会漏掉将来新增的 spawn。
|
||||
*/
|
||||
const liveChildren = new Set();
|
||||
function spawn(...args) {
|
||||
const child = rawSpawn(...args);
|
||||
liveChildren.add(child);
|
||||
child.once('exit', () => liveChildren.delete(child));
|
||||
return child;
|
||||
}
|
||||
process.on('exit', () => {
|
||||
for (const child of liveChildren) {
|
||||
try {
|
||||
child.kill('SIGKILL');
|
||||
} catch {
|
||||
/* 已退出或不可杀:忽略 */
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = 18765;
|
||||
const TLS_PORT = 18772;
|
||||
const ED25519_PORT = 18781;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { TASK_WHITELIST, planTaskCleanup } from '../../scripts/lib/scheduled-tasks.mjs';
|
||||
import { TASK_WHITELIST, isSelfRestartTask, planTaskCleanup } from '../../scripts/lib/scheduled-tasks.mjs';
|
||||
|
||||
/**
|
||||
* na-gui 陈旧计划任务清理(ARCH B-P1-6 / T05)。
|
||||
@@ -100,3 +100,36 @@ test('control.cmd 菜单暴露 cleanup 入口(纯 ASCII + CRLF 由 ps1-encodin
|
||||
assert.match(cmd, /call :RUN cleanup/, 'control.cmd 菜单必须有 cleanup 项转发');
|
||||
assert.match(cmd, /8\)\s*Cleanup stale tasks/, 'control.cmd 菜单应展示 cleanup 项');
|
||||
});
|
||||
|
||||
// ===========================================================================
|
||||
// 自重启任务(2026-10-27 真机发现:卸载漏删 → 僵尸任务反复拉起已删文件)
|
||||
// ===========================================================================
|
||||
|
||||
test('isSelfRestartTask:只认严格命名空间 nodeagent-selfrestart-<数字>', () => {
|
||||
assert.equal(isSelfRestartTask('nodeagent-selfrestart-1793077118968'), true);
|
||||
assert.equal(isSelfRestartTask('nodeagent-selfrestart-123456'), true, '6 位时间戳级仍算');
|
||||
// 以下都不是我们注册的名字,绝不能被当成自重启任务
|
||||
assert.equal(isSelfRestartTask('nodeagent-selfrestart-'), false, '没有数字');
|
||||
assert.equal(isSelfRestartTask('nodeagent-selfrestart-abc123'), false, '非纯数字');
|
||||
assert.equal(isSelfRestartTask('nodeagent-selfrestart-123'), false, '位数过短(非时间戳形态)');
|
||||
assert.equal(isSelfRestartTask('mynodeagent-selfrestart-123456'), false, '前缀必须从头匹配');
|
||||
assert.equal(isSelfRestartTask('nodeagent-selfrestart-123456-extra'), false, '不得带额外后缀');
|
||||
assert.equal(isSelfRestartTask(''), false);
|
||||
assert.equal(isSelfRestartTask(null), false);
|
||||
});
|
||||
|
||||
test('planTaskCleanup:白名单外的自重启任务纳入清理,且仍然只增不误删', () => {
|
||||
const plan = planTaskCleanup([
|
||||
'nodeagent',
|
||||
'nodeagent-selfrestart-1793077118968',
|
||||
'nodeagent-selfrestart-1793077118999',
|
||||
'Adobe Acrobat Update Task', // 用户/第三方任务,绝不能碰
|
||||
'OneDrive Standalone Update',
|
||||
'nodeagent-selfrestart-notatask',
|
||||
]);
|
||||
assert.deepEqual(plan, [
|
||||
'nodeagent',
|
||||
'nodeagent-selfrestart-1793077118968',
|
||||
'nodeagent-selfrestart-1793077118999',
|
||||
], '白名单先出、自重启按名字排序,第三方任务一律不出现');
|
||||
});
|
||||
@@ -85,3 +85,23 @@ test('错误分类:DNS/拒连单独一类,普通错误原样透出', () => {
|
||||
const plain = new Error('boom');
|
||||
assert.equal(describeNetError(plain, 1000), 'boom', '无法归类的错误原样透出,不编造原因');
|
||||
});
|
||||
|
||||
test('describeNetError:TCP 层 ETIMEDOUT 必须给出「配代理」的可执行提示(2026-10-27 真机)', () => {
|
||||
// 真机现场:境内 Windows 直连 github.com:443 → connect ETIMEDOUT 20.205.243.166:443。
|
||||
// 这条最常见,原先落到兜底分支只回一串超时,用户不知道唯一有效动作是配代理。
|
||||
const etimedout = Object.assign(new Error('connect ETIMEDOUT 20.205.243.166:443'), { code: 'ETIMEDOUT' });
|
||||
const msg = describeNetError(etimedout, 20_000);
|
||||
assert.match(msg, /连接超时\/网络不可达/);
|
||||
assert.match(msg, /NA_PROXY/, '必须点明 NA_PROXY 这个具体开关');
|
||||
assert.match(msg, /系统代理/);
|
||||
|
||||
// 同族错误走同一提示
|
||||
for (const code of ['EHOSTUNREACH', 'ENETUNREACH']) {
|
||||
assert.match(describeNetError(Object.assign(new Error('x'), { code }), 1000), /NA_PROXY/, code);
|
||||
}
|
||||
|
||||
// 不得与 ECONNRESET 的「代理或线路问题」混为一谈(两类原因不同)
|
||||
const reset = Object.assign(new Error('read ECONNRESET'), { code: 'ECONNRESET' });
|
||||
assert.match(describeNetError(reset, 1000), /代理或线路/);
|
||||
assert.doesNotMatch(describeNetError(reset, 1000), /NA_PROXY/);
|
||||
});
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
nextFailures,
|
||||
planRestore,
|
||||
readState,
|
||||
rotationTargets,
|
||||
shouldRotate,
|
||||
zeroFailures,
|
||||
} from '../../scripts/lib/startup-guard-core.mjs';
|
||||
import {
|
||||
@@ -447,3 +449,56 @@ test('场景:崩溃三次后第四次守卫执行恢复并归零计数', () =>
|
||||
assert.ok(readFileSync(join(dataDir, 'logs', 'startup-guard.log'), 'utf8').includes('restore'));
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
// ===========================================================================
|
||||
// 日志轮换:看门狗常驻被控端,日志无界增长会把磁盘写满
|
||||
// ===========================================================================
|
||||
|
||||
test('shouldRotate:严格大于阈值才轮换(恰好等于不滚)', () => {
|
||||
assert.equal(shouldRotate(0), false);
|
||||
assert.equal(shouldRotate(1024, 1024), false, '恰好等于阈值不轮换,避免边界抖动');
|
||||
assert.equal(shouldRotate(1025, 1024), true);
|
||||
assert.equal(shouldRotate(Number.NaN, 1024), false, 'NaN(stat 失败)不得触发轮换');
|
||||
});
|
||||
|
||||
test('rotationTargets:从新到旧的 .1 … .N 命名', () => {
|
||||
assert.deepEqual(rotationTargets('/x/startup-guard.log', 3), [
|
||||
'/x/startup-guard.log.1',
|
||||
'/x/startup-guard.log.2',
|
||||
'/x/startup-guard.log.3',
|
||||
]);
|
||||
});
|
||||
|
||||
test('appendGuardLog:超阈值滚存,最旧一份被丢弃,当前日志重新开始', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'na-guard-rotate-'));
|
||||
const dataDir = join(root, 'data');
|
||||
const logPath = join(dataDir, 'logs', 'startup-guard.log');
|
||||
mkdirSync(join(dataDir, 'logs'), { recursive: true }); // 先造出超阈值的大文件,再交给 appendGuardLog 轮换
|
||||
const maxBytes = 200;
|
||||
|
||||
// 三次超阈值写入 → .1 / .2 / .3 依次生成,且每次都留下一条记录
|
||||
for (let i = 1; i <= 3; i += 1) {
|
||||
writeFileSync(logPath, `${'x'.repeat(maxBytes + 10)}\n`);
|
||||
appendGuardLog(dataDir, { action: 'probe', i }, { maxBytes, keep: 3 });
|
||||
}
|
||||
assert.ok(existsSync(`${logPath}.1`), '应生成 .1');
|
||||
assert.ok(existsSync(`${logPath}.2`), '应生成 .2');
|
||||
assert.ok(existsSync(`${logPath}.3`), '应生成 .3');
|
||||
|
||||
// 第四次:.3 被丢弃,.2→.3、.1→.2、当前→.1
|
||||
writeFileSync(logPath, `${'y'.repeat(maxBytes + 10)}\n`);
|
||||
appendGuardLog(dataDir, { action: 'probe', i: 4 }, { maxBytes, keep: 3 });
|
||||
assert.ok(existsSync(`${logPath}.3`), '仍只有 3 份历史');
|
||||
assert.ok(!existsSync(`${logPath}.4`), '不得无限增长出 .4');
|
||||
|
||||
// 当前日志只剩本次一行(可解析 JSON)
|
||||
const lines = readFileSync(logPath, 'utf8').trim().split('\n');
|
||||
assert.equal(lines.length, 1);
|
||||
assert.equal(JSON.parse(lines[0]).i, 4);
|
||||
|
||||
// 未超阈值时只追加,不轮换
|
||||
appendGuardLog(dataDir, { action: 'small' }, { maxBytes, keep: 3 });
|
||||
assert.equal(readFileSync(logPath, 'utf8').trim().split('\n').length, 2);
|
||||
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
});
|
||||
Reference in new issue
Block a user