Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ArcBox is a pure-Rust, high-performance container and VM runtime targeting macOS
**Key layers (bottom-up):**

```text
arcbox (CLI)
abctl (CLI)
↓ gRPC over Unix socket
arcbox-daemon
Expand Down
4 changes: 1 addition & 3 deletions app/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ Covers `arcbox-daemon` (startup/shutdown), `arcbox-core` (`vm_lifecycle`),
`docs/daemon-lifecycle.md` (lock/handoff, residual-state tables) and
`docs/data-directories.md` (filesystem paths) — point there, don't restate.

`arcbox-cli` ships two binaries: `abctl` (the real CLI) and `arcbox` (a
deprecated shim that `exec`s `abctl`, pending removal). User-facing strings
must name `abctl`.
`arcbox-cli` ships one binary, `abctl`. User-facing strings must name it.

## Startup & readiness contract

Expand Down
4 changes: 0 additions & 4 deletions app/arcbox-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ path = "src/lib.rs"
name = "abctl"
path = "src/main.rs"

Comment thread
PeronGH marked this conversation as resolved.
[[bin]]
name = "arcbox"
path = "src/bin/arcbox_placeholder.rs"

[dependencies]
arcbox-core = { workspace = true }
arcbox-docker = { workspace = true }
Expand Down
55 changes: 0 additions & 55 deletions app/arcbox-cli/src/bin/arcbox_placeholder.rs

This file was deleted.

49 changes: 39 additions & 10 deletions app/arcbox-cli/src/commands/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,14 @@ async fn install(format: OutputFormat) -> Result<()> {
tokio::fs::create_dir_all(comp.join("fish")).await?;

// 2. Symlink current executable → ~/.arcbox/bin/abctl (primary).
// Also create ~/.arcbox/bin/arcbox → placeholder for backwards compat.
let exe = std::env::current_exe().context("could not determine current executable path")?;
let exe_dir = exe
.parent()
.context("could not determine executable directory")?;
let symlink_path = bin.join("abctl");
create_or_update_symlink(&exe, &symlink_path).await?;

// The placeholder binary lives next to the main binary.
let placeholder_exe = exe_dir.join("arcbox");
let placeholder_symlink = bin.join("arcbox");
if placeholder_exe.exists() {
create_or_update_symlink(&placeholder_exe, &placeholder_symlink).await?;
}
// Older installs linked ~/.arcbox/bin/arcbox to the rename shim, which no
// longer ships — the link would dangle on PATH. Drop it here rather than in
// `uninstall`, so an upgrade heals without the user removing anything.
remove_stale_shim_link(&bin.join("arcbox")).await;

// 2b. Symlink Docker CLI tools → ~/.arcbox/bin/ if available.
// Tools may be in the app bundle (xbin/) or ~/.arcbox/runtime/bin/.
Expand Down Expand Up @@ -768,6 +762,19 @@ async fn create_or_update_symlink(target: &Path, link: &Path) -> Result<()> {
Ok(())
}

/// Remove the retired `arcbox` shim link left by an older `setup install`.
///
/// Only symlinks are touched: this directory holds nothing but links we
/// created, so a regular file here is the user's and is left alone.
async fn remove_stale_shim_link(link: &Path) {
let Ok(meta) = tokio::fs::symlink_metadata(link).await else {
return;
};
if meta.file_type().is_symlink() {
let _ = tokio::fs::remove_file(link).await;
}
}

/// Remove a directory if it exists, ignoring errors.
async fn remove_dir_if_exists(path: &Path) {
let _ = tokio::fs::remove_dir_all(path).await;
Expand All @@ -777,6 +784,28 @@ async fn remove_dir_if_exists(path: &Path) {
mod tests {
use super::*;

#[tokio::test]
async fn stale_shim_link_is_removed_but_a_real_file_is_kept() {
let dir = tempfile::tempdir().unwrap();

// A dangling link to the retired shim: the upgrade case.
let link = dir.path().join("arcbox");
tokio::fs::symlink(dir.path().join("gone"), &link)
.await
.unwrap();
remove_stale_shim_link(&link).await;
assert!(tokio::fs::symlink_metadata(&link).await.is_err());

// A regular file of the same name is not ours to delete.
let file = dir.path().join("arcbox-file");
tokio::fs::write(&file, b"user data").await.unwrap();
remove_stale_shim_link(&file).await;
assert_eq!(tokio::fs::read(&file).await.unwrap(), b"user data");

// Absent path is a no-op, not an error.
remove_stale_shim_link(&dir.path().join("absent")).await;
}

#[test]
fn detect_zsh_from_env() {
// detect_shell() reads $SHELL — just verify the function doesn't panic.
Expand Down
4 changes: 2 additions & 2 deletions app/arcbox-daemon/src/nfs_mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ async fn reconcile(
// The trigger is the lifecycle *ready* edge, never the restart generation:
// that counter is bumped when the VM stops, so acting on it would send the
// request into the gap where no guest exists and burn the retry budget on a
// VM that is still booting — or, after a plain `arcbox stop`, on one that is
// not coming back until the next on-demand start.
// VM that is still booting — or, after a plain `abctl machine stop`, on
// one that is not coming back until the next on-demand start.
let mut state = runtime.subscribe_system_vm_state();
let mut first = true;

Expand Down
1 change: 0 additions & 1 deletion docs/data-directories.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ execution.
| Path | Purpose | Creator |
|------|---------|---------|
| `bin/abctl` | CLI symlink | cli (`abctl setup install`) |
| `bin/arcbox` | Compatibility symlink → abctl | cli (`abctl setup install`) |
| `bin/arcbox-daemon` | Fallback daemon binary path | cli |
| `bin/arcbox-agent` | Guest agent binary | daemon (bundle seed / boot cache) |
| `bin/vm-agent` | Sandbox microVM init binary (guest sees `/arcbox/bin/vm-agent`) | daemon (bundle seed / boot cache) |
Expand Down
Loading