pkgmgr gc --report lists each linked worktree and orphaned .claude/worktrees/agent-* dir with its size and last activity, the changes a cleanup would keep, the biggest children of every --root, ELF core dumps, docker system df with --docker, and free versus attributed space per filesystem; --json prints the same as JSON. It deletes and writes nothing and refuses --apply. git run() gains input_text for cat-file --batch-check. 🎯 Fix: 90 % 💥 Break: 2 % 💸 Cost: new ⏱️ Time: new 🛡️ Security: 100 % 🏆 Score: 88 🚦 Gate: cost new, time new: cleared by the operator's commit word for pkgmgr gc --report (2026-11-07) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
124 lines
3.8 KiB
Python
124 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from pkgmgr.actions.gc.report.render import render_text
|
|
|
|
NOW = 1_000_000.0
|
|
|
|
|
|
def report(**overrides: object) -> dict:
|
|
base = {
|
|
"generated_at": NOW,
|
|
"threshold_bytes": 1 << 20,
|
|
"worktrees": [
|
|
{
|
|
"path": "/r/.worktrees/x",
|
|
"branch": None,
|
|
"orphaned": False,
|
|
"missing": False,
|
|
"size_bytes": 3 << 30,
|
|
"last_activity": NOW - 2 * 86400,
|
|
"foreign_entries": 4,
|
|
},
|
|
{
|
|
"path": "/r/.claude/worktrees/agent-1",
|
|
"branch": None,
|
|
"orphaned": True,
|
|
"missing": False,
|
|
"size_bytes": 5 << 20,
|
|
"last_activity": NOW - 90,
|
|
"foreign_entries": 0,
|
|
},
|
|
],
|
|
"preserved": [
|
|
{
|
|
"path": "/r/.worktrees/x",
|
|
"branch": None,
|
|
"paths": 2,
|
|
"preserved": False,
|
|
"reasons": [
|
|
"detached HEAD reachable from no ref",
|
|
"a: content in no ref",
|
|
],
|
|
}
|
|
],
|
|
"roots": [
|
|
{
|
|
"root": "/tmp",
|
|
"children": [
|
|
{
|
|
"path": "/tmp/core",
|
|
"kind": "core-dump",
|
|
"size_bytes": 2 << 20,
|
|
"newest_mtime": NOW - 3 * 3600,
|
|
}
|
|
],
|
|
}
|
|
],
|
|
"core_dumps": [
|
|
{
|
|
"path": "/tmp/core",
|
|
"size_bytes": 2 << 20,
|
|
"apparent_bytes": 1 << 30,
|
|
"mtime": NOW - 3 * 3600,
|
|
}
|
|
],
|
|
"docker": None,
|
|
"balance": [
|
|
{
|
|
"filesystem": "/",
|
|
"total_bytes": 100 << 30,
|
|
"free_bytes": 10 << 30,
|
|
"attributed_bytes": 3 << 30,
|
|
}
|
|
],
|
|
"warnings": ["docker unavailable: not installed"],
|
|
}
|
|
return {**base, **overrides}
|
|
|
|
|
|
class TestRenderText(unittest.TestCase):
|
|
def test_sections_and_rows(self) -> None:
|
|
lines = render_text(report()).splitlines()
|
|
|
|
self.assertIn("== worktrees", lines)
|
|
worktree = next(line for line in lines if line.endswith("/r/.worktrees/x"))
|
|
self.assertEqual(
|
|
worktree.split(),
|
|
["3.0G", "2.0d", "4", "linked", "(detached)", "/r/.worktrees/x"],
|
|
)
|
|
orphan = next(line for line in lines if "agent-1" in line)
|
|
self.assertEqual(orphan.split()[1:5], ["1.5m", "0", "orphaned", "-"])
|
|
verdict = next(line for line in lines if line.startswith("no "))
|
|
self.assertIn(
|
|
"detached HEAD reachable from no ref; a: content in no ref", verdict
|
|
)
|
|
self.assertIn("== root /tmp (over 1.0M)", lines)
|
|
rows = [line.split() for line in lines]
|
|
self.assertIn(["2.0M", "1.0G", "3.0h", "/tmp/core"], rows)
|
|
self.assertIn(["/", "100.0G", "10.0G", "3.0G"], rows)
|
|
self.assertEqual(lines[-1], "WARN docker unavailable: not installed")
|
|
self.assertNotIn("== docker", lines)
|
|
|
|
def test_docker_rows_and_empty_sections(self) -> None:
|
|
docker = [
|
|
{
|
|
"type": "Images",
|
|
"total": 3,
|
|
"active": 1,
|
|
"size": "1GB",
|
|
"reclaimable": "0B",
|
|
}
|
|
]
|
|
|
|
text = render_text(report(docker=docker, core_dumps=[], warnings=[]))
|
|
|
|
self.assertIn("== core dumps\n(none)", text)
|
|
self.assertIn("== docker", text)
|
|
self.assertIn("Images 3 1 1GB 0B", text)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|