Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b3ea5c9
chore(xtask): scaffold CLI with 6 subcommand stubs
houko Mar 22, 2026
f2e6d54
feat(xtask): implement 6 build automation subcommands
houko Mar 22, 2026
bd5132d
docs(xtask): add README with usage for all 6 subcommands
houko Mar 22, 2026
ac937ee
chore(justfile): delegate ci/release/sync-versions to xtask
houko Mar 22, 2026
370e1ae
chore: remove shell scripts replaced by xtask
houko Mar 22, 2026
0aa974a
fix(xtask): align release/sync-versions logic with original shell scr…
houko Mar 22, 2026
f08dd27
fix(xtask/release): match shell script behavior exactly
houko Mar 22, 2026
345ae4b
fix(xtask/release): validate CalVer format before using version in gi…
houko Mar 22, 2026
235cc75
chore(justfile): add build-web recipe delegating to xtask
houko Mar 22, 2026
53fb3f7
feat(xtask): add 8 new subcommands (publish-sdks, dist, docker, setup…
houko Mar 22, 2026
3e998db
fix(xtask): resolve clippy warnings (ptr_arg, redundant_guards)
houko Mar 22, 2026
edd3d5d
chore: add cargo xtask alias in .cargo/config.toml
houko Mar 22, 2026
6ea1309
feat(xtask): add bench, migrate, fmt-check, clean-all, doctor subcomm…
houko Mar 22, 2026
367fb9b
refactor(xtask): rename fmt-check to fmt
houko Mar 22, 2026
bcbc736
fix(xtask/migrate): call librefang-migrate library directly instead o…
houko Mar 22, 2026
6093c5f
fix(api): use config_ref() accessor for private kernel config field
houko Mar 22, 2026
db43899
feat(xtask): add 8 new commands (dev, db, license-check, loc, update-…
houko Mar 22, 2026
921d5b0
feat(xtask): migrate remaining scripts to xtask (contributors, publis…
houko Mar 22, 2026
88fa0f2
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
dc4bd4c
docs: add [inbox] config to init template and configuration docs (EN/ZH)
houko Mar 22, 2026
2421607
feat(cli): add hash-password command for Argon2id dashboard password …
houko Mar 22, 2026
26d8fae
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
eee6ec8
refactor(ci): migrate ci.yml to use xtask commands
houko Mar 22, 2026
c3b20bf
fix(xtask): resolve clippy warnings (ptr_arg, div_ceil, too_many_argu…
houko Mar 22, 2026
a787d83
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
f0cf1c1
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
3024e7f
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
52feee2
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
582105c
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
d05959c
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
a044a4b
refactor(xtask): extract repo_root() into shared common module
houko Mar 22, 2026
94a5139
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 2026
8c4d96e
Merge branch 'main' into feat/xtask-automation
github-actions[bot] Mar 22, 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
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"
8 changes: 3 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ jobs:
librsvg2-dev \
patchelf
- name: Check formatting
run: cargo fmt --check
run: cargo xtask fmt
- name: Run clippy
run: cargo clippy --workspace --all-targets -- -D warnings
run: cargo xtask ci --no-test --no-web

# ── Security audit (independent) ─────────────────────────────────────────────────────
security:
Expand All @@ -52,16 +52,14 @@ jobs:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-audit
run: cargo install cargo-audit --locked
- name: Run security audit
run: |
# Ignore known vulnerabilities without fix:
# - GTK/webkit: transitive from Tauri 2.x
# - lexical-core: transitive through imap (imap 3.x is alpha, nom 8+ required)
# - rsa: Marvin Attack timing side-channel, no fix available (transitive from librefang-channels)
# - rustls-webpki 0.102.x: transitive from rumqttc, no compatible upgrade available
cargo audit \
cargo xtask deps --audit \
--ignore RUSTSEC-2024-0384 \
--ignore RUSTSEC-2024-0385 \
--ignore RUSTSEC-2024-0412 \
Expand Down
18 changes: 10 additions & 8 deletions .github/workflows/release-shell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,12 @@ jobs:
- name: Publish CLI binaries to npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: |
export VERSION="${GITHUB_REF#refs/tags/v}"
bash scripts/publish-npm-binaries.sh
VERSION="${GITHUB_REF#refs/tags/v}"
cargo xtask publish-npm-binaries \
--version "$VERSION" \
--repo "${{ github.repository }}" \
--tag "${{ github.ref_name }}"

# ── CLI Binary → PyPI ──────────────────────────────────────────────────
cli_pypi:
Expand All @@ -388,11 +389,12 @@ jobs:
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
REPO: ${{ github.repository }}
TAG: ${{ github.ref_name }}
run: |
export VERSION="${GITHUB_REF#refs/tags/v}"
bash scripts/publish-pypi-binaries.sh
VERSION="${GITHUB_REF#refs/tags/v}"
cargo xtask publish-pypi-binaries \
--version "$VERSION" \
--repo "${{ github.repository }}" \
--tag "${{ github.ref_name }}"

# ── Sync to Homebrew Tap ──────────────────────────────────────────────
sync_homebrew:
Expand Down
15 changes: 4 additions & 11 deletions .github/workflows/update-contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,13 @@ jobs:
steps:
- uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"

- name: Generate contributors SVG
env:
GITHUB_TOKEN: ${{ github.token }}
run: python3 scripts/generate_contributors.py librefang/librefang web/public/assets/contributors.svg
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Generate star history SVG
- name: Generate contributors and star history SVGs
env:
GITHUB_TOKEN: ${{ github.token }}
run: python3 scripts/generate_star_history.py librefang/librefang web/public/assets/star-history.svg
run: cargo xtask contributors --repo librefang/librefang

- name: Create PR with updated SVGs
id: cpr
Expand Down
44 changes: 35 additions & 9 deletions Cargo.lock

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

46 changes: 46 additions & 0 deletions crates/librefang-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,16 @@ enum Commands {
#[arg(long)]
keep_config: bool,
},
/// Generate an Argon2id password hash for dashboard authentication.
#[command(
name = "hash-password",
long_about = "Generate an Argon2id password hash for use with dashboard_pass_hash in config.toml.\n\nIf --password is not provided, prompts for interactive input.\n\nExamples:\n librefang hash-password # Interactive prompt\n librefang hash-password --password 'secret' # Inline (less secure, visible in shell history)"
)]
HashPassword {
/// Password to hash (omit for interactive prompt).
#[arg(long)]
password: Option<String>,
},
}

#[derive(Subcommand)]
Expand Down Expand Up @@ -1695,6 +1705,7 @@ fn main() {
confirm,
keep_config,
}) => cmd_uninstall(confirm, keep_config),
Some(Commands::HashPassword { password }) => cmd_hash_password(password),
}
}

Expand Down Expand Up @@ -7045,6 +7056,41 @@ fn cmd_vault_remove(key: &str) {
}
}

// ---------------------------------------------------------------------------
// hash-password command
// ---------------------------------------------------------------------------

fn cmd_hash_password(password: Option<String>) {
let pass = match password {
Some(p) => p,
None => {
let p1 = prompt_input("Enter password: ");
if p1.is_empty() {
ui::error("Password cannot be empty.");
std::process::exit(1);
}
let p2 = prompt_input("Confirm password: ");
if p1 != p2 {
ui::error("Passwords do not match.");
std::process::exit(1);
}
p1
}
};

match librefang_api::password_hash::hash_password(&pass) {
Ok(hash) => {
println!("\n{hash}\n");
println!("Add to config.toml:");
println!(" dashboard_pass_hash = \"{hash}\"");
}
Err(e) => {
ui::error(&format!("Failed to hash password: {e}"));
std::process::exit(1);
}
}
}

// ---------------------------------------------------------------------------
// Scaffold commands (librefang new skill/integration)
// ---------------------------------------------------------------------------
Expand Down
9 changes: 9 additions & 0 deletions crates/librefang-cli/templates/init_default_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ debounce_ms = 500
# memory_limit = "512m"
# timeout_secs = 60

# ── File Inbox (Async External Commands) ────────────────────
# Drop text files into a directory to send messages to agents.
# First line may contain `agent:<name>` to target a specific agent.
# [inbox]
# enabled = false
# directory = "~/.librefang/inbox/" # Defaults to $HOME_DIR/inbox/
# poll_interval_secs = 5
# default_agent = "assistant" # Agent to use when no agent: directive

# ── Network (P2P Federation) ─────────────────────────────────
# network_enabled = false
# [network]
Expand Down
77 changes: 77 additions & 0 deletions docs/src/app/configuration/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Complete reference for `config.toml`, covering every configurable field in the L
- [\[canvas\]](#canvas)
- [\[auto\_reply\]](#auto_reply)
- [\[broadcast\]](#broadcast)
- [\[inbox\]](#inbox)
- [\[\[bindings\]\]](#bindings)
- [\[pairing\]](#pairing)
- [\[extensions\]](#extensions)
Expand Down Expand Up @@ -2045,6 +2046,82 @@ routes = { "announcement-channel" = ["agent-a", "agent-b", "agent-c"] }

---

### `[inbox]`

File-based input inbox for async external commands. Drop text files into a watched directory and they are dispatched as messages to agents. Processed files are moved to a `processed/` subdirectory to avoid redelivery.

```toml
[inbox]
enabled = true
directory = "~/.librefang/inbox/"
poll_interval_secs = 5
default_agent = "assistant"
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `enabled` | bool | `false` | Enable the inbox directory watcher. |
| `directory` | string or null | `null` | Directory to watch. Defaults to `$HOME_DIR/inbox/`. Supports `~` expansion. |
| `poll_interval_secs` | u64 | `5` | How often (in seconds) to scan the directory for new files. Minimum 1. |
| `default_agent` | string or null | `null` | Agent name to route files to when no `agent:` directive is found in the file. |

**File format:** Plain text files (`.txt`, `.md`, `.json`, `.py`, etc.). The first line may contain an `agent:<name>` directive to target a specific agent; the rest is sent as the message body. Files without the directive use `default_agent`.

**Safety limits:** Files larger than 1 MB are skipped. Binary files (non-text extensions) are skipped. Empty files are moved to `processed/` without sending.

**Usage examples:**

Target a specific agent:

```bash
cat > ~/.librefang/inbox/task.txt << 'EOF'
agent:code-reviewer
Please review this code for security issues:

def login(user, password):
query = f"SELECT * FROM users WHERE name='{user}' AND pass='{password}'"
return db.execute(query)
EOF
```

Send to the default agent:

```bash
echo "Summarize today's system logs" > ~/.librefang/inbox/summarize.txt
```

Cron job:

```bash
# crontab -e
0 9 * * * grep ERROR /var/log/app.log > ~/.librefang/inbox/daily_errors.txt
```

CI/CD post-build:

```bash
echo "agent:devops
Build failed, please analyze:
$(tail -100 build.log)" > ~/.librefang/inbox/build_$(date +%s).txt
```

Batch processing:

```bash
for doc in ~/reports/*.md; do
cp "$doc" ~/.librefang/inbox/
done
```

Check inbox status:

```bash
curl -s http://127.0.0.1:4545/api/inbox/status
# {"enabled":true,"pending_count":3,"processed_count":12,...}
```

---

### `[[bindings]]`

Agent bindings route specific channel/account/peer combinations to specific agents. More specific bindings (more non-null fields) take priority over less specific ones.
Expand Down
Loading