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

13 KiB
Raw Blame History

name, description
name description
unidesk-gc 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 留存或安全停止判定前,必须先读该文档。

本机流程

先执行只读归因:

df -h /
df -BG /
bun scripts/cli.ts gc plan --target-use-percent 69 --limit 50

默认计划存在缺口时,显式启用候选类别:

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

复核计划后,只执行相同候选范围:

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 临时预算:

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 镜像候选:

bun scripts/cli.ts server cleanup plan --min-age-hours 24 --limit 80
  • 返回零个过期镜像候选时,不得使用 docker image prunedocker system prune
  • 受保护镜像可能仍是当前运行或回滚真相。

默认 BuildKit 清理可能因缓存均较新而实际释放 0B。只有明确止压时才使用 --build-cache-all

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 管理:

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 级。
  • 提取必要证据并确认没有活跃写入者后,可以删除该目录:
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 策略并只生成计划:

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

复核候选后才允许执行:

bun scripts/cli.ts gc remote <providerId> merged-worktrees run --confirm

周期 stage 通过以下入口核对 YAML 字段、stage 和 inSync

bun scripts/cli.ts gc remote <providerId> policy plan
bun scripts/cli.ts gc remote <providerId> policy status

内存分布与 Kubernetes 留存

先用紧凑 overview 归因真实内存压力:

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 历史对象手动回收固定使用:

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/meminfoMemAvailable
    • 输出必须披露 metric=MemAvailablesource=/proc/meminfoswapExcluded=true
    • swap 只作为独立压力信号,绝不计入启动可用量;
    • 启动门槛和比较语义只读取 config/hwlab-node-lanes.yaml#templates.hwlabV03.webProbeWorkbench.resourcePolicy.memoryStartGuard
    • 文档、skill、源码和测试不得复制 thresholdBytes 的当前数值;
    • 除非用户明确授权修改 WebProbe 启动门槛,否则不得改变 owning YAML 的 thresholdBytes
  • 人工处置命令必须按顺序执行:
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;
    • PIDPPIDSIDstartTicks 与后代进程能闭合为唯一身份;
    • 任一证据缺失或存在歧义时继续标记 protected。
  • 精确终止:
    • TERM 前重新核对 PID/PPID/SID/startTicks,防止 PID 复用;
    • 只向已核实的唯一进程树发送 TERM
    • 按 YAML 定义的有界等待时间重新枚举;
    • 仍未退出时,只以不可变的 PID/startTicks 复核残留身份;
    • 同时披露原始与当前 PPID/SID,允许 TERM 后重挂载但不放宽 PID 复用保护;
    • 只对复核后的同一残留进程树发送 KILL。
  • 禁止批量终止:
    • 不得使用 pkill -f chromekillall chrome 或其他按进程名批量终止方式;
    • 证据不完整或归属存在歧义时保持 protected,不得猜测。
  • 终止后验证:
    • 确认目标 PID、后代 PID 和 session/process group 全空;
    • 确认 active observer 未受影响;
    • 重新采集 /proc/meminfoMemAvailable、独立 swap 信号、observer 状态和 Chrome/runner 摘要;
    • 结构化记录判定证据、TERM/KILL 结果、残留进程与终止前后资源数据。

JD01 等远端节点只能显式启用可重建工具缓存:

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 prunedocker 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 追求目标百分比。

验证

使用以下有界证据收口:

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 百分比、主要清理类别、受保护失败和剩余高风险压力源。