Files
pikasTech-unidesk/.agents/skills/unidesk-gc/SKILL.md
T
2026-07-21 09:44:04 +02:00

299 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: unidesk-gc
description: >-
UniDesk 磁盘 GC 与主机压力处置流程。用于 `bun scripts/cli.ts gc ...`
根盘高水位、worktree/缓存/日志清理、Web observe/Chrome 内存压力和安全停止判定。
---
# UniDesk GC
- 处理 UniDesk 磁盘或内存压力时,优先使用受控 UniDesk CLI。
- 到达保护边界后停止,不得扩大为临时 `rm -rf`、Docker prune、数据库清理、原生 Kubernetes 删除或运行时状态删除。
- 长期规则以 `docs/reference/gc.md` 为准。
- 执行远端 GC、k3s/PVC 归因、Web observe/Chrome 压力处置、registry/CI 留存或安全停止判定前,必须先读该文档。
## 本机流程
先执行只读归因:
```bash
df -h /
df -BG /
bun scripts/cli.ts gc plan --target-use-percent 69 --limit 50
```
默认计划存在缺口时,显式启用候选类别:
```bash
bun scripts/cli.ts gc plan --target-use-percent 69 --limit 2000 \
--include-tool-caches \
--include-stale-tmp \
--include-vscode-stale-servers \
--include-vscode-stale-extensions \
--include-vscode-cached-vsix \
--include-baidu-staging \
--include-state-artifacts \
--include-state-stale-scratch \
--include-codex-sessions \
--include-merged-worktrees \
--include-vpn-diagnostic-logs
```
复核计划后,只执行相同候选范围:
```bash
bun scripts/cli.ts gc run --confirm --target-use-percent 69 --limit 2000 \
--include-tool-caches \
--include-stale-tmp \
--include-vscode-stale-servers \
--include-vscode-stale-extensions \
--include-vscode-cached-vsix \
--include-baidu-staging \
--include-state-artifacts \
--include-state-stale-scratch \
--include-codex-sessions \
--include-merged-worktrees \
--include-vpn-diagnostic-logs
```
worktree 因 merge/cherry 超时而受保护时,只提高 worktree 临时预算:
```bash
bun scripts/cli.ts gc plan --target-use-percent 69 --limit 2000 \
--include-merged-worktrees \
--worktree-scan-budget-ms 120000 \
--worktree-cherry-check-timeout-ms 10000 \
--no-file-logs --no-docker-logs --no-journal --no-build-cache --no-tmp --no-db-summary
```
- 只对计划仍显示的候选执行匹配的 `run --confirm`
- dirty、近期、活跃、未合并或超时保护的 worktree 必须继续受保护。
## 缓存与日志
单独检查 Docker 镜像候选:
```bash
bun scripts/cli.ts server cleanup plan --min-age-hours 24 --limit 80
```
- 返回零个过期镜像候选时,不得使用 `docker image prune``docker system prune`
- 受保护镜像可能仍是当前运行或回滚真相。
默认 BuildKit 清理可能因缓存均较新而实际释放 `0B`。只有明确止压时才使用 `--build-cache-all`
```bash
bun scripts/cli.ts gc plan --target-use-percent 69 --build-cache-all --limit 50 \
--no-file-logs --no-docker-logs --no-journal --no-tmp --no-db-summary
bun scripts/cli.ts gc run --confirm --target-use-percent 69 --build-cache-all --limit 50 \
--no-file-logs --no-docker-logs --no-journal --no-tmp --no-db-summary
```
Journald 上限也通过同一 CLI 管理:
```bash
bun scripts/cli.ts gc plan --target-use-percent 69 --journal-target-size 128M --limit 50 \
--no-file-logs --no-docker-logs --no-build-cache --no-tmp --no-db-summary
```
计划可接受时,使用参数完全匹配的 `run --confirm`
## 临时转储
- `/tmp/unidesk-cli-output` 保存超大 JSON/stdout。
- 截断的 plan/run 会持续写入新转储,因此 GC 诊断时可能增长到 GiB 级。
- 提取必要证据并确认没有活跃写入者后,可以删除该目录:
```bash
fuser -v /tmp/unidesk-cli-output 2>&1 || true
rm -rf -- /tmp/unidesk-cli-output
```
重复出现时应补受控 CLI 留存策略,不得把手工删除变成常规入口。
- 其他 `/tmp` 目录先检查大小、mtime 和活跃 fd。
- 未明确归属和可重建性时,不得删除可能属于并行任务的当日 source/workspace scratch。
## 远端节点
- provider host 统一使用 `bun scripts/cli.ts gc remote <providerId> ...`
- 远端长任务必须异步执行,并用 `status --job-id` 短查询,不得维持长 SSH 会话。
### 已合并 worktree
先读取 YAML 策略并只生成计划:
```bash
bun scripts/cli.ts gc remote <providerId> merged-worktrees plan
```
- 仅枚举 Git 登记且位于 `workspaceRoots` 的 worktree
- dirty、活跃、近期、未被 `baseRef` 吸收、cherry 检查超时和主 worktree 必须显示为 protected
- 手动入口与 policy timer 复用同一筛选器,批量上限分别读取 YAML 的手动和自动字段;
- 执行前逐项重新计划,只允许 `git worktree remove`,不得删除 branch 或使用 `rm -rf`
复核候选后才允许执行:
```bash
bun scripts/cli.ts gc remote <providerId> merged-worktrees run --confirm
```
周期 stage 通过以下入口核对 YAML 字段、stage 和 `inSync`
```bash
bun scripts/cli.ts gc remote <providerId> policy plan
bun scripts/cli.ts gc remote <providerId> policy status
```
### 内存分布与 Kubernetes 留存
先用紧凑 overview 归因真实内存压力:
```bash
bun scripts/cli.ts gc remote <providerId> memory-distribution
```
- 默认一次输出物理内存、PSS、进程 swap、cgroup、zombie 和 Kubernetes 对象分布;
- 同一结果必须直接披露 `processes.topSwap`,以及 zombie 父进程的 Kubernetes Pod 归属、
泄露分类和处置类别,避免额外执行 `ps`、cgroup 映射和 `kubectl` 拼接;
- swap 单独披露,不能计入 WebProbe 启动资格;
- 需要完整明细时才使用 `--full`
发现大量 zombie 时不得尝试终止 zombie。先按 overview 的 owner 定位长期父进程,
修复子进程回收路径,再通过正常自动交付滚动 owner。运行面重启只能清除既有 zombie,
不能替代源码修复。
Kubernetes 历史对象手动回收固定使用:
```bash
bun scripts/cli.ts gc remote <providerId> retention plan --limit 500
bun scripts/cli.ts gc remote <providerId> retention run --confirm --limit 500
bun scripts/cli.ts gc remote <providerId> status --job-id <id>
```
- 筛选、保留窗口、分组、批量和级联策略只来自目标节点的 `kubernetesObjectRetention` YAML
- 多 namespace 必须由共享 `defaults` 与显式 `policies` 表达:
- 一个 `retention plan` 聚合显示全部 policy
- 每个 policy 使用唯一 `configId` 和不会随 commit 变化的稳定 owner 分组标签;
- CLI `--limit` 是每个 policy 的上限,并继续受对应 YAML 单批上限约束;
- 根级 `aggregatePreviewLimit` 控制聚合样例数,默认 overview 不得依赖第二次 `--full` 才能判断。
- 手动入口与 `policyTimer.includeKubernetesObjectRetention` 自动阶段必须复用同一筛选器;
- 活跃、过新、未知分组、时间不可解析、扫描截断和 Table 形状漂移全部保护;
- 只删除 YAML 指定的根对象,通过 ownerRef 级联,不直接删除下游 TaskRun、Pod、Secret 或 Event
- 自动回收由 `gc remote <providerId> policy plan|install --confirm|status` 管理,周期和单批上限由 YAML 控制。
- `policy status` 必须一次披露期望与安装态的配置/runner 指纹、policy 数量、各 namespace 关键留存字段和 `inSync`
- owning YAML 变化后只通过 `policy install --confirm` 收敛安装态,禁止直接修改 host JSON、runner 或 systemd unit。
## WebProbe 低内存人工处置
- 唯一资格指标:
- 只读取 `/proc/meminfo``MemAvailable`
- 输出必须披露 `metric=MemAvailable``source=/proc/meminfo``swapExcluded=true`
- swap 只作为独立压力信号,绝不计入启动可用量;
- 启动门槛和比较语义只读取 `config/hwlab-node-lanes.yaml#templates.hwlabV03.webProbeWorkbench.resourcePolicy.memoryStartGuard`
- 文档、skill、源码和测试不得复制 `thresholdBytes` 的当前数值;
- 除非用户明确授权修改 WebProbe 启动门槛,否则不得改变 owning YAML 的 `thresholdBytes`
- 人工处置命令必须按顺序执行:
```bash
bun scripts/cli.ts gc remote <node> plan --memory-pressure-only
bun scripts/cli.ts gc remote <node> run --confirm --memory-pressure-only
bun scripts/cli.ts gc remote <node> status --job-id <id>
bun scripts/cli.ts gc remote <node> memory
```
- 顺序约束:
- 默认 scoped plan 必须直接披露 YAML 限量候选摘要和 `runEligibility`,一次输出即可判断;
- 只有 `runEligibility.allowed=true` 时才允许执行明确标记安全的内存压力候选;
- `--full` 只用于下钻完整身份明细,不得作为 scoped run 的默认前置步骤;
- `run` 返回 job id 后,重复执行 `status --job-id <id>` 直到终态;
- job 未终态时不得提前执行 `memory` 或重试 WebProbe
- 终态后执行 `memory`,只有不再命中 owning YAML 的 `manualComparator` 时才可重试人工启动;
- 内存处置不得改用未带 `--memory-pressure-only` 的通用 plan/run。
- sentinel cadence
- 命中 owning YAML 的 `sentinelComparator` 时返回 `skipped-wait-next-round`
- 不创建 observer、不启动 Chromium、不自动执行 GC
- 等待下一轮 cadence 重新读取 `MemAvailable`
以下远端场景必须先读 `docs/reference/gc.md`
- G14 registry/CI workspace 留存、k3s/PVC 归因和安全停止判定;
- PK01 pikanode 临时目录留存与 Docker provider 安全边界;
- JD01 k3s/PVC 归因,以及 NC01/JD01 Web observe artifact、Chrome/observer 内存增长与 YAML-first 真相源核对。
## Web observe 与 Chrome 逃逸进程
- 正常生命周期:
- 远端节点的 Chrome 内存增长应先按 observer 生命周期问题处理;
- sentinel/quick-verify 的全部终态必须停止对应 observer;
- runner 的 TTL、maxSamples 和 artifact cap 必须来自 YAML
- 归属尚未判清时不得按名称终止 Chrome,也不得删除 web-observe 目录。
- 保护边界:
- active observer、受控任务仍引用的浏览器会话及其完整进程树始终受保护。
- 只有独立且无归属的 Playwright `cliDaemon`/Chrome 进程树才可进入精确终止:
- 存活时间超过 owning YAML 定义的异常存活窗口;
- 受控 observe/sentinel 状态未显示该进程树归属于 active observer 或在途受控任务;
- manifest、heartbeat、PID/session 记录均不能把它归属到有效 run;
- `PID``PPID``SID``startTicks` 与后代进程能闭合为唯一身份;
- 任一证据缺失或存在歧义时继续标记 protected。
- 精确终止:
- TERM 前重新核对 `PID/PPID/SID/startTicks`,防止 PID 复用;
- 只向已核实的唯一进程树发送 TERM;
- 按 YAML 定义的有界等待时间重新枚举;
- 仍未退出时,只以不可变的 `PID/startTicks` 复核残留身份;
- 同时披露原始与当前 `PPID/SID`,允许 TERM 后重挂载但不放宽 PID 复用保护;
- 只对复核后的同一残留进程树发送 KILL。
- 禁止批量终止:
- 不得使用 `pkill -f chrome``killall chrome` 或其他按进程名批量终止方式;
- 证据不完整或归属存在歧义时保持 protected,不得猜测。
- 终止后验证:
- 确认目标 PID、后代 PID 和 session/process group 全空;
- 确认 active observer 未受影响;
- 重新采集 `/proc/meminfo``MemAvailable`、独立 swap 信号、observer 状态和 Chrome/runner 摘要;
- 结构化记录判定证据、TERM/KILL 结果、残留进程与终止前后资源数据。
JD01 等远端节点只能显式启用可重建工具缓存:
```bash
bun scripts/cli.ts gc remote JD01 plan --target-use-percent 49 --include-tool-caches --limit 100
bun scripts/cli.ts gc remote JD01 run --confirm --target-use-percent 49 --include-tool-caches --limit 100
```
- 必须先复核 plan。
- 候选仅限固定 allowlist 的 npm/npx/Bun 缓存。
- 不得改用 `rm -rf ~/.npm ~/.bun`,也不得触碰 `node_modules`、auth/config、k3s/containerd、PVC 或 Docker volume。
## 保护边界
以下对象不得作为通用磁盘止压目标:
- `docker system prune``docker image prune`、Docker/Compose volume 删除;
- 未经 `gc db-trace`、备份和维护窗口的 PostgreSQL PGDATA/trace 清理;
- `/var/lib/containerd``/var/lib/rancher/k3s``/var/lib/kubelet`、PVC、registry blob、runtime snapshot
- Codex auth/config/profilesession 仅能通过 `--include-codex-sessions` 清理,活跃 SQLite 日志还需 `fuser` 与专门留存决策;
- 以下 Web observe 与 Chrome 对象:
- active run 和 live observer runner
- 归属或 stale 分类未闭合的 Chrome process tree
- 缺少 manifest/heartbeat/pid/open-fd 证据的 web-observe state root
- 只有按“Web observe 与 Chrome 逃逸进程”完成无归属判定的唯一进程树才可精确终止。
- dirty、active、unmerged、recent 或 timeout-protected worktree
- 用户未明确要求时的 `backend-core` rebuild/restart/replacement。
- 低风险候选执行后仍为 `summary.target.safeStop=true` 时,停止并报告剩余压力源与决策选项。
- 不得绕过 CLI 追求目标百分比。
## 验证
使用以下有界证据收口:
```bash
df -h /
df -BG /
docker system df
du -sh /root/unidesk/.worktree /root/unidesk/.state /tmp /var/log 2>/dev/null || true
```
- 远端内存/Chrome 压力还需记录 `free -h`、Chrome/observer 摘要与 web-observe state 大小。
- 总结起止 `df` 百分比、主要清理类别、受保护失败和剩余高风险压力源。