Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
885008b
feat(clean): add biwa clean command to remove stale remote directories
risu729 Mar 22, 2026
153c5a9
style: apply automated fixes
autofix-ci[bot] Mar 22, 2026
68c4c7a
fix: address PR review comments
risu729 Mar 22, 2026
d957c41
style: fix clippy match_same_arms and absolute_paths lints
risu729 Mar 22, 2026
6267b2a
build: allow MPL-2.0 license for dirs dependency
risu729 Mar 22, 2026
fa161db
refactor(clean): store local state under XDG state directory
risu729 Mar 22, 2026
46cdd8d
fix(clean): address PR review (pid file, concurrency, quota, find)
risu729 Mar 22, 2026
67232e4
fix(clean): address Copilot follow-up (quota *, cache scope, docs usage)
risu729 Mar 22, 2026
bca7377
refactor(state): rename cache module to state
risu729 Mar 22, 2026
5bc5b3c
refactor(config): resolve config dir via dirs::config_dir
risu729 Mar 22, 2026
6b4421e
fix(clean): harden remote cleanup, daemon PID, and config validation
risu729 Mar 23, 2026
5f50f35
fix(clean): address PR review on quota parse, schema keys, orphan safety
risu729 Mar 23, 2026
e7e4c8a
revert: manual cli docs modification
risu729 Mar 23, 2026
63eb36d
fix(clean): prevent e2e cleanup races and document cleanup behavior
risu729 Mar 23, 2026
159a98b
feat(config): add configurable clean state dir resolution
risu729 Mar 23, 2026
3eadb92
style: apply automated fixes
autofix-ci[bot] Mar 23, 2026
2bab401
style: apply automated fixes (attempt 2/3)
autofix-ci[bot] Mar 23, 2026
9265658
refactor(config): move state_dir to root Config
risu729 Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,33 @@ include = ["/README.md", "/src/**/*.rs"]

[dependencies]
bytes = "=1.11.1"
chrono = { version = "=0.4.44", features = ["serde"] }
clap = { version = "=4.6.0", features = ["derive"] }
color-eyre = "=0.6.5"
confique = { version = "=0.4.0", features = ["json5", "toml", "yaml"] }
console = "=0.16.3"
derive_more = { version = "=2.1.1", features = ["deref"] }
dialoguer = "=0.12.0"
dirs = "=6.0.0"
duct = "=1.1.1"
gethostname = "=1.1.0"
globset = "=0.4.18"
hex = "=0.4.3"
homedir = "=0.3.6"
humantime = "=2.3.0"
ignore = "=0.4.25"
indicatif = "=0.18.4"
itertools = "=0.14.0"
json5 = "=1.3.1"
nix = { version = "=0.31.2", features = ["process", "signal"] }
russh = { version = "=0.58.0", default-features = false, features = [
"flate2",
"ring",
"rsa"
] }
russh-sftp = "=2.1.1"
schemars = "=1.2.1"
scopeguard = "=1.2.0"
serde = { version = "=1.0.228", features = ["derive"] }
serde_json = "=1.0.149"
serde_yaml = "=0.9.34"
Expand Down
8 changes: 8 additions & 0 deletions biwa.usage.kdl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ allow = [
"BSD-3-Clause",
"ISC",
"CC0-1.0",
"MPL-2.0",
]
unused-allowed-license = "deny"
unused-license-exception = "deny"
Expand Down
25 changes: 25 additions & 0 deletions docs/src/cli/clean.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions docs/src/cli/clean/stop.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions docs/src/cli/index.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions docs/src/sync-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,39 @@ biwa run -d /tmp/my-project --sync ls

When used with `biwa sync`, `--remote-dir` replaces the automatically computed `remote_root + project_name` path.
To prevent accidental data overwrites when executing standard commands across different remote paths, **using `-d` with `biwa run` automatically disables project synchronization (`--skip-sync`)**. If you want to sync your project to a custom directory and run a command there in one step, you must explicitly pass the `--sync` flag.

## Remote directory cleanup

Biwa stores each successful `biwa sync` and `biwa run` (after sync, when applicable) in local state under your [XDG state directory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) (for example `~/.local/state/biwa/connections.json` on Linux). That lets the tool know which remote project directories belong to this machine and when they were last used.

### Automatic cleanup after sync and run

When **`clean.auto`** is `true` (the default), biwa may start a **background** `biwa clean --auto` process after a successful `biwa sync` or `biwa run`, as long as password authentication is not interactive-only (non-interactive auth such as env password, key, or agent is required). You can turn this off globally with **`BIWA_CLEAN_AUTO=false`** or in config:

```toml
[clean]
auto = false
```

Automatic cleanup connects over SSH, reads disk **quota** usage when the server reports it, and applies **`[clean]`** rules:

- **`max_age`** — Maximum age for remote directories under the default layout (`remote_root` + per-project folder names). Expressed as a duration (`"30d"`, `"12h"`, a plain number for minutes, and so on). This acts as the baseline “0% quota” threshold.
- **`quota_thresholds`** — Optional map of quota usage **percentages** (0–100) to maximum directory ages. When reported quota usage is at or above a threshold, directories older than that threshold’s age can be removed. If quota data is unavailable, only the baseline age from `max_age` applies.

Candidates for removal are **tracked** connection entries that are older than the effective age limit, plus **orphan** directories on the server that look like default biwa project folders under `remote_root` but are no longer listed in local state—**only** when local state already has at least one tracked path for that SSH target (so orphan detection is not run on an empty or broken state file).

Background cleanup does not run if another cleanup process already holds the PID lock, or if interactive password auth would be required.

### Manual `biwa clean`

Use the dedicated command for explicit control; see the [CLI reference for `biwa clean`](/cli/clean.md).

- **Default (no extra flags)** — Remove the **current project’s** remote directory (from the computed `remote_root` + unique project name for the current working directory).
- **`--all`** — Remove every **tracked** remote directory for this SSH host/user/port that matches the default biwa layout under `remote_root`.
- **`--purge`** — Remove **all** directory entries listed under `remote_root` on the server (including projects from other clients). Use with care.
- **`--dry-run`** — Print what would be removed without deleting.
- **`biwa clean stop`** — Stop a running background cleanup daemon (if any).

Flags are resolved in a fixed order when combined: **`--auto`** (daemon-style quota cleanup) takes precedence over **`--purge`**, then **`--all`**, then the default current-project clean.

For explicit clean invocations, biwa stops any running background cleanup daemon first so manual and automatic cleanup do not run at the same time.
46 changes: 46 additions & 0 deletions schema/config.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading