Add remote gc for provider hosts

This commit is contained in:
Codex
2026-05-29 01:43:14 +00:00
parent 3d5e613674
commit 3b9c8d8ddb
6 changed files with 1506 additions and 6 deletions
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -3,6 +3,7 @@ import { closeSync, existsSync, ftruncateSync, lstatSync, mkdirSync, openSync, r
import { basename, join, resolve } from "node:path";
import { type UniDeskConfig, repoRoot, rootPath } from "./config";
import { runRemoteGcCommand } from "./gc-remote";
type GcRisk = "low" | "medium" | "high" | "blocked";
type GcItemKind =
@@ -183,6 +184,10 @@ const TMP_EXACT_PROTECT = new Set([
export async function runGcCommand(config: UniDeskConfig, args: string[]): Promise<unknown> {
const [action = "plan", ...rest] = args;
if (action === "remote") {
const [providerId, subaction = "plan", ...remoteArgs] = rest;
return await runRemoteGcCommand(config, providerId, subaction, remoteArgs);
}
if (action === "policy") {
const [subaction = "plan", ...policyArgs] = rest;
const options = parseGcPolicyOptions(policyArgs);
@@ -243,7 +248,7 @@ export async function runGcCommand(config: UniDeskConfig, args: string[]): Promi
ok: false,
error: "unsupported-gc-action",
action,
supportedActions: ["plan", "run", "db-trace", "policy"],
supportedActions: ["plan", "run", "db-trace", "policy", "remote"],
};
}
+14 -3
View File
@@ -18,7 +18,7 @@ export function rootHelp(): unknown {
{ command: "server swap status|ensure [--path /swapfile] [--size 2GiB] [--dry-run]", description: "Inspect or idempotently create host swap for low-memory main-server operation." },
{ command: "server logs [--tail-bytes N]", description: "Return bounded tails from file logs and docker logs." },
{ command: "server cleanup plan [--min-age-hours N] [--limit N]", description: "Dry-run Docker image cleanup plan only: list active/protected images, stale candidates older than the default 24h threshold, risk, estimated reclaim, and manual review commands without deleting anything." },
{ command: "gc plan|run|db-trace|policy [--confirm] [--logs-keep-days N] [--include-browser-cache]", description: "One-time main-server disk relief and low-risk anti-bloat policy for logs, journald, allowlisted /tmp artifacts and explicit trace telemetry retention; plan is read-only and run requires --confirm." },
{ command: "gc plan|run|db-trace|policy|remote [--confirm] [--logs-keep-days N] [--include-browser-cache]", description: "One-time main-server or remote provider disk relief and low-risk anti-bloat policy for logs, journald, allowlisted /tmp artifacts, scoped core dumps and explicit trace telemetry retention; plan is read-only and run requires --confirm." },
{ command: "server rebuild <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "Maintenance-only local Compose rebuild for reviewed main-server services; frontend standard release must use CI artifact plus deploy apply dev/prod artifact consumers." },
{ command: "provider attach <providerId> [--master-server URL] [--up] [--force] | provider triage <providerId> [--observed-error text] [--observed-scope scope] [--microservice id ...] [--full|--raw]", description: "Generate the minimal external provider-gateway env/compose bundle or run the low-noise read-only provider health triage contract." },
{ command: "ssh <route> [operation args...]", description: "Open a Host SSH / WSL SSH maintenance session through the provider-gateway bridge; route syntax such as `G14:k3s` or `D601:win/c/test` only locates distributed targets." },
@@ -263,7 +263,7 @@ function providerHelp(): unknown {
function gcHelp(): unknown {
return {
command: "gc plan|run|db-trace|policy",
command: "gc plan|run|db-trace|policy|remote",
output: "json",
usage: [
"bun scripts/cli.ts gc plan",
@@ -275,9 +275,12 @@ function gcHelp(): unknown {
"bun scripts/cli.ts gc db-trace run --confirm --before-date 2026-05-25 --vacuum-full",
"bun scripts/cli.ts gc policy plan",
"bun scripts/cli.ts gc policy install",
"bun scripts/cli.ts gc remote G14 plan",
"bun scripts/cli.ts gc remote G14 run --confirm",
"bun scripts/cli.ts gc remote G14 status --job-id <id>",
"bun scripts/cli.ts gc plan --full",
],
description: "Plan or execute bounded one-time main-server disk relief for file logs, Docker json logs, systemd journal, Docker BuildKit cache, allowlisted /tmp artifacts and explicitly scoped database trace telemetry retention.",
description: "Plan or execute bounded one-time disk relief for file logs, Docker json logs, systemd journal, Docker BuildKit cache, allowlisted /tmp artifacts, scoped remote core dumps and explicitly scoped database trace telemetry retention.",
safety: {
default: "plan is read-only and mutation=false",
runGuard: "run requires --confirm",
@@ -293,6 +296,13 @@ function gcHelp(): unknown {
"--build-cache-until DURATION": "prune Docker builder cache unused for duration; default 24h",
"--build-cache-all": "prune all Docker builder cache without an until filter",
"--tmp-min-age-hours N": "delete allowlisted /tmp artifacts older than N hours; default 24",
"--core-dump-min-age-hours N": "remote only: delete untracked allowlisted core.<pid> dumps older than N hours; default 1",
"--no-core-dumps": "remote only: do not include scoped core dump cleanup candidates",
"--include-hwlab-registry": "remote G14 only: opt in to conservative HWLAB registry tag retention plus official registry garbage-collect",
"--registry-gc-only": "remote G14 only: run official registry garbage-collect without deleting additional tags; intended for interrupted registry retention recovery",
"--registry-keep-per-repo N": "remote registry only: keep at least N newest tags per service repo; default 20, minimum 10",
"--registry-min-age-hours N": "remote registry only: keep all tags newer than N hours; default 48, minimum 24",
"--job-id ID": "remote status only: inspect a long-running remote gc job",
"--limit N": "number of candidates returned and executed by run when --full is not set; default 50",
"--result-limit N": "number of per-candidate run results returned when --full is not set; default 50",
"--full|--raw": "return and run against all candidates rather than the default bounded page",
@@ -300,6 +310,7 @@ function gcHelp(): unknown {
"db-trace --before-date YYYY-MM-DD": "plan or delete default trace telemetry event types before the date",
"db-trace run --vacuum-full": "rewrite public.oa_events after deletion so df can reclaim disk; requires maintenance window",
"policy plan|install": "render or install journald caps and a daily file-log plus allowlisted /tmp low-risk gc systemd timer",
"remote <providerId> plan|run": "run bounded GC through UniDesk SSH passthrough on a provider host; G14 protects HWLAB k3s/runtime/PVC/workspace paths, and HWLAB registry retention is explicit opt-in with workload-ref, recent-tag and per-repo tag protection",
"--no-file-logs|--no-docker-logs|--no-journal|--no-build-cache|--no-tmp|--no-db-summary": "disable one collector",
},
reference: "docs/reference/cli.md",
+10
View File
@@ -2309,6 +2309,16 @@ async function runSshCaptureRemoteCommand(config: UniDeskConfig, invocation: Par
});
}
export async function runSshCommandCapture(config: UniDeskConfig, target: string, args: string[], input?: string): Promise<SshCaptureResult> {
const invocation = parseSshInvocation(target, args);
const parsed = invocation.parsed;
if (parsed.remoteCommand === null) throw new Error(`ssh ${target} capture requires a non-interactive operation`);
const stdin = parsed.stdinPrefix !== undefined || parsed.stdinSuffix !== undefined
? `${parsed.stdinPrefix ?? ""}${input ?? ""}${parsed.stdinSuffix ?? ""}`
: input;
return await runSshCaptureRemoteCommand(config, invocation, parsed.remoteCommand, stdin);
}
function writeChunkedStdin(stdin: NodeJS.WritableStream, input: string): void {
const buffer = Buffer.from(input, "utf8");
const chunkSize = 32 * 1024;