sasurahime 0.1.21

macOS developer cache cleaner — scan and wipe stale caches from 40+ tools
---
title: "sasurahime: Rust 製 macOS キャッシュクリーナーの哲学と全機能"
emoji: "🗑️"
type: "tech"
topics: ["rust", "macos", "cli", "キャッシュクリーン", "sasurahime"]
published: false
---

## なぜ作ったのか

開発用 Mac のストレージ管理画面を開くと、いつも「その他」がやけに幅を利かせています。

あれの正体はだいたい決まっていて──`uv` がダウンロードした PyPI アーカイブのキャッシュ、Homebrew が取り置いた古い Formula のダウンロード、`mise` が取り残した旧 Node ランタイム、Playwright や Puppeteer が取り込んだブラウザの過去ビルド、`cargo` のレジストリキャッシュ、Docker や Colima のイメージ、Go や Deno や Rustup のビルドキャッシュ、Gradle や Maven や SwiftPM の依存キャッシュ……。

それぞれのツールには個別のクリーンコマンドが存在します。しかし、それらを毎回個別に思い出して実行するのは面倒です。そもそも「何がどれだけあるか」を一覧で見る手段がなく、気づいたときには SSD が 100GB 単位で埋まっている。

この問題を解決するために `sasurahime` を作りました。

## 名前の由来

「掃除」というコンセプトに合う名前を探していて、日本神話の大祓詞に登場する **速佐須良比売(ハヤサスラヒメ)** にたどり着きました。

川から海へ、海から根の国へと流れていった穢れを、最後に受け取って**跡形もなく消し去る**女神です。不要になったキャッシュを完全に消し去る、という役割にぴったりだと思い、そのままプロジェクト名にしました。

ターミナルで打ちやすい文字列であることも決め手のひとつです。

## 設計思想

### detect は絶対に削除しない

すべてのクリーナーが `Cleaner` トレイトを実装しています:

```rust
trait Cleaner {
    fn name(&self) -> &str;
    fn detect(&self) -> ScanResult;
    fn clean(&self, dry_run: bool) -> Result<CleanResult>;
}
```

`detect()` はスキャンのみ行い、絶対にファイルを削除しません。`clean(dry_run: true)` も同様です。この「副作用ゼロの検出」は最も重要な設計ルールです。`scan` サブコマンドで気軽に状況を確認できるのはこのおかげです。

### デフォルトで Trash モード

削除されたファイルはデフォルトで **macOS の Trash(ゴミ箱)** に移動されます。つまり、Finder から復元できます。間違って消してしまっても、ゴミ箱を開ければ戻せるという安心感があります。

完全に削除したい場合のみ `--permanent` フラグを指定します。`--yes` と組み合わせたときは「本当に全部消しますか?」という確認プロンプトが追加で表示されるようになっています。

### 外部コマンドのモック

`uv` や `brew` のような外部コマンドは `CommandRunner` トレイトを介して呼び出します。テスト時にはモックに差し替えられるため、実際のツールがインストールされていない CI 環境でもテストが通ります。

## 対応しているターゲット一覧

現時点で **40 以上**のターゲットが実装されています。一覧は `sasurahime targets` でいつでも確認できます。

主要なものをカテゴリ別に紹介します。

### 言語・パッケージマネージャ

| ターゲット | 対象 |
|---|---|
| uv | `~/.cache/uv/` の古い simple-vN ディレクトリ、`uv cache prune` |
| brew | Homebrew の古いダウンロードとバージョン (`brew cleanup -s --prune=all`) |
| bun, go, pip, npm, yarn, pnpm, pipx, poetry, conda | 各パッケージマネージャのキャッシュ |
| cargo | Cargo registry キャッシュ + `target/` ディレクトリ |
| rustup | 未使用の Rust ツールチェーン |
| deno | Deno キャッシュ |
| gradle, maven | Gradle 旧バージョンキャッシュ、Maven ローカルリポジトリ |
| spm (SwiftPM) | SwiftPM キャッシュ |
| cocoa-pods | CocoaPods キャッシュ |
| flutter | Flutter/Dart pub キャッシュ |

### ランタイム・ツール

| ターゲット | 対象 |
|---|---|
| mise | `~/.local/share/mise/installs/` の未使用ランタイム(設定ファイルとクロスチェック) |
| browsers | Puppeteer / Playwright の古いブラウザビルド(最新を残す) |
| node-gyp | node-gyp ビルドキャッシュ |

### Docker / VM

| ターゲット | 対象 |
|---|---|
| docker | `docker system prune`(イメージ・コンテナ・ビルドキャッシュ) |
| colima | Colima VM ディスクキャッシュ |
| orbstack | Orbstack プルーン |

### IDE・シミュレータ

| ターゲット | 対象 |
|---|---|
| xcode | Xcode DerivedData / アーカイブ |
| device-support | iOS DeviceSupport の古いシンボル(最新 N バージョンを保持) |
| simulator | iOS Simulator キャッシュ (`xcrun simctl delete unavailable`) |
| jetbrains | JetBrains IDE キャッシュ |
| vscode-extensions | VS Code 拡張キャッシュ |
| trash | macOS Trash のサイズ報告 |

### AI/ML・CI

| ターゲット | 対象 |
|---|---|
| huggingface | Hugging Face モデルキャッシュ (`hub/`) |
| ollama | Ollama モデルキャッシュ |
| act | GitHub Actions ローカルランナーキャッシュ |
| pre-commit | pre-commit フック環境キャッシュ |

### ログ・その他

| ターゲット | 対象 |
|---|---|
| logs | `~/.local/share/kilo/log/` の古いログ |
| library-logs | `~/Library/Logs/` の開発者ログ |
| downloads | `~/Downloads` の古いファイル |

各クリーナーは独立したファイルに分かれているため、新しい対象を追加するときは `Cleaner` トレイトを実装した struct をひとつ足すだけで済みます。

## 全コマンドリファレンス

### `sasurahime`

引数なしで実行するとインタラクティブ TUI が起動します。全ターゲットをスキャンしたあと、`dialoguer::MultiSelect` で削除する対象を選択します。

```bash
sasurahime
```

実際の動作はこんな感じです。

```
sasurahime v0.1.5
Scanning uv... [OK]
Scanning brew... [OK]
Scanning mise... [OK]
Scanning browsers... [OK]
Scanning xcode... [OK]
Scanning logs... [OK]

Select caches to clean  [space to toggle, enter to confirm]:
> [ ] uv                   3.6 GB
  [ ] brew                 75.1 MB
  [ ] logs                 43.5 MB
  [ ] act                  201.2 MB
  [ ] huggingface          1.1 GB
  [ ] pre-commit           242.8 MB
  [ ] library-logs         291.5 KB
  [ ] colima               100.3 GB
```

スペースで選択、Enter で確定します。確認プロンプトが表示されたら `y` で削除実行です。

```
Will free approximately 118.6 MB.
Proceed? [y/N]
```

削除中はスピナーと経過表示が出ます。

```
⠈ Cleaning brew...                                                  Freed: 54.5 MB
Cleaning brew... [OK]
⠙ Cleaning logs...                                                  [kilo] Removed: ...
Cleaning logs... [OK]                                                Removed 2 log files

Total freed: 98.0 MB
```

### `sasurahime scan`

削除はせず、スキャン結果だけを一覧表示します。

```bash
sasurahime scan
```

### `sasurahime clean <target>`

特定のターゲットだけを掃除します。

```bash
sasurahime clean uv
sasurahime clean brew
sasurahime clean mise
sasurahime clean browsers
sasurahime clean logs
```

### `sasurahime clean <target> --dry-run`

何も削除せずに、どれだけの容量が解放できるかをプレビューします。

```bash
sasurahime clean uv --dry-run
```

### `sasurahime --yes`

すべてのクリーナーを順番に実行します。確認プロンプトは出るので、無人実行には `--yes --permanent` を組み合わせます(その場合も最終確認は表示されます)。

```bash
sasurahime --yes
```

### `sasurahime --permanent`

Trash を経由せず完全に削除します。デフォルトの Trash モードをオーバーライドするためのフラグです。

```bash
sasurahime clean uv --permanent
```

### `sasurahime targets`

対応している全ターゲットの一覧を表示します。

```bash
sasurahime targets
```

### `sasurahime --version`

バージョン番号を表示します。

## 安全性の詳細

### uchg フラグの自動解除

macOS ではファイルに `uchg`(ユーザー immutable)フラグが立っていると、`rm -rf` でも削除できません。sasurahime は削除の直前に `chflags -R nouchg <path>` を実行してから削除します。

### mise のピン留め保護

`~/.config/mise/config.toml` やプロジェクトの `.mise.toml` に書かれているバージョンは削除されません。HOME 以下の最大深さ 5 まで `.mise.toml` を探しに行き、そこで pin されているバージョンを削除対象から除外します。

```toml
# .mise.toml に書かれている node 18 は絶対に消さない
[tools]
node = "18"
```

### Trash モードの設定ファイル

`~/.config/sasurahime/config.toml` に `trash_mode = false` と書けば、`--permanent` をつけなくても常に完全削除モードになります。

## インストール方法

### GitHub Releases(推奨)

プリビルドバイナリをダウンロードして配置するだけです。

```bash
curl -LO https://github.com/armaniacs/sasurahime/releases/download/v0.1.5/sasurahime-aarch64-apple-darwin.tar.gz
tar xzf sasurahime-x86_64-apple-darwin.tar.gz
sudo mv sasurahime /usr/local/bin/
```

### Cargo(Rust 環境がある場合)

```bash
cargo install sasurahime
```

## 実装のハイライト

### バイナリサイズ 872KB

Rust で書かれているとはいえ、`clap`、`dialoguer`、`indicatif`、`comfy-table`、`toml`、`serde`、`trash` といくつかの依存関係があります。リリースプロファイルで以下の最適化を施し、最終的なバイナリサイズは **872KB** になりました。

```toml
[profile.release]
opt-level      = "z"
strip          = true
lto            = true
codegen-units  = 1
panic          = "abort"
```

### トレイトによる拡張性

`Cleaner` トレイトのおかげで、新しいキャッシュ対象を追加するときは 1 ファイル + 数行の登録コードだけで完結します。実際に、最初のリリースから 3 回のアップデートでクリーナー数が倍以上に増えました。

### 外部コマンドの注入

`std::process::Command` を直接呼ばず、`CommandRunner` トレイトを経由することで、テストではモックに差し替えられるようになっています。これにより、`brew` が入っていない CI でも BrewCleaner のテストが動きます。

## さいごに

sasurahime はまだ v0.1.5 のプロジェクトです。「このキャッシュも掃除したい」「こういう機能がほしい」という要望があれば、Issue や PR を歓迎しています。

すぐに試したい方はこちらから:

```bash
cargo install sasurahime
sasurahime
```

スキャン結果を見て「こんなにあったのか」と驚くところから始まると思います。私がそうでした。