Commit Graph

95 Commits

Author SHA1 Message Date
argenis de la rosa
69232d0eaa feat(workspace): add registry storage and lifecycle CLI 2026-03-05 05:47:40 -05:00
Argenis
bc923335cb
Merge pull request #2793 from zeroclaw-labs/issue-2747-clippy-critical-debt-dev
chore(quality): reduce high-impact clippy debt in critical modules
2026-03-05 01:54:41 -05:00
argenis de la rosa
6e014e3b51 chore(quality): reduce high-impact clippy debt in critical modules 2026-03-04 21:29:05 -05:00
argenis de la rosa
e2d65aef2a feat(security): add canary and semantic guardrails with corpus updater 2026-03-04 06:20:45 -05:00
Argenis
9deed8d066
fix(gateway): persist --new-pairing reset safely (#1967) 2026-02-26 09:33:16 -05:00
Reid
676708bc29
feat(gateway): add --new-pairing flag to regenerate pairing code (#1957)
- Base branch target (`dev`):
  - Problem: Regenerating a pairing code requires manually editing `config.toml` to clear `paired_tokens` — error-prone,
  undiscoverable, and harder when using non-default config paths (`ZEROCLAW_CONFIG_DIR`, workspace overrides).
  - Why it matters: Web dashboard users may need to re-pair (new browser, cleared session, token rotation, shared
  workstation). A one-flag solution eliminates manual config surgery.
  - What changed: Added `--new-pairing` flag to `zeroclaw gateway`. When passed, it clears all stored paired tokens via
  `config.save()` (respects whatever config path is active) before `PairingGuard::new()` initializes, which triggers automatic
  generation of a fresh 6-digit pairing code.
  - What did **not** change (scope boundary): `PairingGuard` internals, `run_gateway` signature, config schema, pairing protocol,
   token format.

  Closes: #1956

  ## Label Snapshot (required)

  - Risk label: `risk: low`
  - Size label: `size: XS`
  - Scope labels: `gateway`
  - Module labels: `gateway: pairing`
  - If any auto-label is incorrect: N/A

  ## Change Metadata

  - Change type: `feature`
  - Primary scope: `gateway`

  ## Linked Issue

  - Closes #<issue_number>

  ## Supersede Attribution

  N/A

  ## Validation Evidence (required)

  ```bash
  cargo fmt --all -- --check   # pass
  cargo clippy --all-targets -- -D warnings  # zero new warnings
  cargo build  # pass

  Manual verification:
  zeroclaw gateway --help        # --new-pairing flag visible in help text
  zeroclaw gateway --new-pairing # prints "Cleared paired tokens" log, displays fresh 6-digit code
  # config.toml: paired_tokens = [] persisted

  - Evidence provided: build pass, manual CLI test
  - If any command is intentionally skipped: cargo test — no new logic that warrants unit tests (flag wiring + existing
  config.save() + existing PairingGuard::new() empty-token path)

  Security Impact (required)

  - New permissions/capabilities? No
  - New external network calls? No
  - Secrets/tokens handling changed? No — uses existing config.save() and PairingGuard::new() code paths
  - File system access scope changed? No
  - Note: --new-pairing intentionally invalidates all existing sessions. This is the expected behavior for credential rotation.

  Privacy and Data Hygiene (required)

  - Data-hygiene status: pass
  - Redaction/anonymization notes: N/A
  - Neutral wording confirmation: Yes

  Compatibility / Migration

  - Backward compatible? Yes — flag is opt-in, default false
  - Config/env changes? No
  - Migration needed? No

  i18n Follow-Through

  - i18n follow-through triggered? No

  Human Verification (required)

  - Verified scenarios: --new-pairing clears tokens and displays fresh code; omitting the flag preserves existing tokens as
  before
  - Edge cases checked: flag with no prior tokens (still works, generates code as normal)
  - What was not verified: non-default config paths (logic delegates to existing config.save() which already handles
  ZEROCLAW_CONFIG_DIR and workspace overrides)

  Side Effects / Blast Radius (required)

  - Affected subsystems/workflows: Gateway startup path only, when --new-pairing is explicitly passed
  - Potential unintended effects: None — existing behavior unchanged without the flag
  - Guardrails: INFO log line confirms token clearing; pairing code display confirms new code generated

  Agent Collaboration Notes (recommended)

  - Agent tools used: Claude Code
  - Verification focus: compilation, flag wiring, config persistence path-independence
  - Confirmation: naming + architecture boundaries followed

  Rollback Plan (required)

  - Fast rollback: git revert <commit>
  - Feature flags or config toggles: N/A — CLI flag, no persistent state change beyond what user requested
  - Observable failure symptoms: --new-pairing flag unrecognized (would mean revert succeeded)

  Risks and Mitigations

  - Risk: User accidentally passes --new-pairing and invalidates all active sessions
    - Mitigation: Flag is explicit and long-form only (no short alias), INFO log clearly states what happened
2026-02-26 09:22:34 -05:00
argenis de la rosa
c4ba69b6bf feat(cli): add self-update command
Implements self-update functionality that downloads the latest release
from GitHub and replaces the current binary.

Features:
- `zeroclaw update` - downloads and installs latest version
- `zeroclaw update --check` - checks for updates without installing
- `zeroclaw update --force` - forces update even if already latest
- Cross-platform support (Linux, macOS, Windows)
- Atomic binary replacement on Unix, rename+copy on Windows
- Platform-specific archive handling (.tar.gz on Unix, .zip on Windows)

Closes #1352

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:12:02 +08:00
Allen Huang
6064890415 feat: goals engine, heartbeat delivery, daemon improvements, and cron consolidation
- goals: add autonomous goal loop engine for long-term goal execution
- goals: add goal-level reflection for stalled goals
- goals: make GoalStatus and StepStatus deserialization self-healing
- goals: remove initiative planning from Rust, use cron job instead
- daemon: add PID lock and goal-loop supervisor
- daemon: add per-task failure tracking and auto-disable for heartbeat
- daemon: deliver heartbeat results to configured channels
- cron: add nightly consolidation cron job
- cron: set delete_after_run for one-shot shell jobs
- cron: add session_source to agent prompt building
- service: forward provider env vars into generated service files
- agent: add reflection flywheel — cron context injection, tool audit, nightly consolidation
- agent: make state reconciliation opt-in per call site

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-26 01:50:24 +08:00
Chummy
938d900106 fix(build): include coordination module in binary crate 2026-02-25 23:16:27 +08:00
FlashFamily
931cf40636 fix: resolve all clippy warnings across codebase
Fix all clippy errors reported by `cargo clippy --all-targets -- -D warnings`
on Rust 1.93, covering both the original codebase and upstream dev changes.

Changes by category:
- format!() appended to String → write!/writeln! (telegram, discord)
- Redundant field names, unnecessary boolean not (agent/loop_)
- Long numeric literals (wati, nextcloud, telegram, gemini)
- Wildcard match on single variant (security/leak_detector)
- Derivable Default impls (config/schema)
- &Option<T> → Option<&T> or allow (config/schema, config/mod, gateway/api)
- Identical match arms merged (gateway/ws, observability, providers, main, onboard)
- Cast truncation allowed with rationale (discord, lark)
- Unnecessary borrows/returns removed (multiple files)
- Unused imports removed (channels/mod, peripherals/mod, tests)
- MSRV-gated APIs allowed locally (memory/hygiene, tools/shell, tools/screenshot)
- Unnecessary .get().is_none() → !contains_key() (gemini)
- Explicit iteration → reference loop (gateway/api)
- Test-only: useless vec!, field_reassign_with_default, doc indentation

Validated: cargo fmt, cargo clippy --all-targets -- -D warnings, cargo test
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 49e90cf3e4)
2026-02-25 17:50:56 +08:00
Allen Huang
b36dd3aa81 feat(logging): use local timezone for log timestamps
Replace default UTC timer with ChronoLocal::rfc_3339() so daemon and
CLI log lines display the operator's local time, making correlation
with external events easier.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-24 23:02:13 +08:00
Chummy
99bf8f29be fix(unsafe-debt): remove runtime unsafe UID check and forbid unsafe code (RMN-37 RMN-38) 2026-02-24 18:30:36 +08:00
reidliu41
8f263cd336 feat(agent): add CLI parameters for runtime config overrides 2026-02-24 18:12:33 +08:00
Chummy
59d4f7d36d feat: stabilize codex oauth and add provider model connectivity workflow 2026-02-24 12:24:51 +08:00
reidliu41
04e8eb2d8e feat(models): add list, set, and status subcommands 2026-02-23 08:09:28 +08:00
Chummy
a36b1466ff feat(security): add otp and estop phase-1 foundation 2026-02-21 23:19:36 +08:00
InuDial
9f844173b8 Use channels(&self) and channels_except_webhook(&self)
to reduce repeat
2026-02-21 19:38:19 +08:00
chumyin0912@gmail.com
77262d1ed4 style: apply rustfmt in auth refresh handler 2026-02-21 19:06:45 +08:00
Aleksandr Prilipko
38029c1e78 fix(auth): add Gemini OAuth refresh CLI support and fix ManagedOAuth bearer token
Fixes two related issues with Gemini OAuth:

1. CLI command `zeroclaw auth refresh --provider gemini` was hardcoded to
   only support OpenAI Codex, making manual token refresh impossible for
   Gemini profiles. Extended the CLI handler to support both providers.

2. GeminiProvider.build_generate_content_request() was missing bearer token
   for ManagedOAuth auth type. The method applied OAuth bearer token only
   for CLI OAuth (GeminiAuth::OAuthToken), but not for managed profiles
   (GeminiAuth::ManagedOAuth), causing 401 Unauthorized errors even after
   successful token refresh.

Changes:
- src/main.rs: AuthCommands::Refresh now handles both openai-codex and
  gemini providers via pattern match
- src/providers/gemini.rs: Extended OAuth bearer token handling to include
  GeminiAuth::ManagedOAuth case (line 837)

Verification:
- Manual test: zeroclaw auth refresh --provider gemini --profile second
- E2E test: echo "hello" | zeroclaw agent --provider gemini --model gemini-2.5-pro
- Unit tests: cargo test providers::gemini (38 passed)

Risk: Low (isolated auth flow changes, no API contract changes)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-21 18:53:11 +08:00
Aleksandr Prilipko
d56c061896 refactor(auth): add Gemini OAuth and consolidate OAuth utilities (DRY)
- Add src/auth/gemini_oauth.rs: Full Gemini/Google OAuth2 implementation
  - PKCE authorization code flow with loopback redirect
  - Device code flow for headless environments
  - Token refresh with automatic expiration handling
  - Stdin fallback for remote/headless OAuth callback capture

- Add src/auth/oauth_common.rs: Shared OAuth utilities
  - PkceState struct and generate_pkce_state()
  - url_encode/url_decode (RFC 3986)
  - parse_query_params for URL parameter parsing
  - random_base64url for cryptographic random generation

- Update src/auth/mod.rs: Add Gemini support to AuthService
  - store_gemini_tokens() for saving OAuth tokens
  - get_valid_gemini_access_token() with automatic refresh
  - get_gemini_profile() for provider initialization

- Update src/main.rs: Generic PendingOAuthLogin
  - Consolidate PendingOpenAiLogin and PendingGeminiLogin into generic struct
  - Reduce 10 functions to 4 generic functions
  - Support both openai-codex and gemini providers in auth commands

- Update src/providers/gemini.rs: ManagedOAuth authentication
  - GeminiAuth enum with ApiKey and ManagedOAuth variants
  - new_with_auth() constructor for OAuth-based authentication
  - Automatic token refresh via AuthService integration

- Update src/providers/mod.rs: Wire GeminiProvider with AuthService

Net reduction: ~290 lines of duplicated code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-21 18:53:11 +08:00
Chummy
628654ebe5 fix: improve allowed_roots guidance for filesystem access 2026-02-21 17:33:11 +08:00
BenedictKing
816cf74552 fix(cli): use Cargo.toml version instead of hardcoded string
Replace hardcoded `version = "0.1.0"` in clap command attribute with
`version` (no value), which makes clap read from CARGO_PKG_VERSION
automatically. This ensures `zeroclaw -V` always reflects the version
defined in Cargo.toml.
2026-02-21 17:26:38 +08:00
Chummy
61f98a8fd3 feat(observability): add runtime trace diagnostics and trace doctor query 2026-02-21 17:00:38 +08:00
chumyin0912@gmail.com
179e7949c2 fix(gateway): align dashboard API client and embed built web assets 2026-02-21 16:14:01 +08:00
chumyin0912@gmail.com
81b05deb64 fix(test): include hooks field after rebase 2026-02-21 15:12:27 +08:00
Allen Huang
7d81715b60 fix(agent): skip interactive approval in daemon/cron context
Daemon heartbeat and cron tasks called agent::run() which hardcoded
channel_name as "cli" and always created an ApprovalManager, causing
[Y]es / [N]o / [A]lways stdin prompts on the unattended daemon terminal.

Add interactive parameter to agent::run(): CLI passes true (preserving
approval flow), daemon/cron pass false (no ApprovalManager, channel
marked as "daemon").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-21 14:52:44 +08:00
xj
0638266b63 feat(hooks): integrate HookRunner into agent loop, channels, and gateway
Thread Option<&HookRunner> into run_tool_call_loop with hook fire points
for LLM input, before/after tool calls. Add hooks field to
ChannelRuntimeContext for message received/sending interception.
Build HookRunner from config in run_gateway and fire gateway_start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:34:09 +08:00
Jayson Reis
aff9ef91cf fix(onboard): make model refresh and doctor model checks async-safe 2026-02-21 13:03:10 +08:00
xiaotianxt
bf08f1a1bb fix(cli): restore shared command enum wiring 2026-02-21 11:57:29 +08:00
xiaotianxt
b1694b63a9 refactor(cli): reuse shared command enums from lib 2026-02-21 11:57:29 +08:00
Jayson Reis
0523e655f8 refactor(auth): make auth profile store async 2026-02-21 02:25:23 +08:00
Chummy
78358c53b3 fix(onboard): require explicit overwrite confirmation for existing config 2026-02-21 02:25:21 +08:00
reidliu41
3eb084454e feat(memory): add zeroclaw memory CLI management commands
ZeroClaw's memory system powers context injection, auto-save, and long-term agent identity — but until now users had
**zero visibility** into what's stored. No way to list, inspect, audit, or clean up memory outside the agent loop.

`zeroclaw memory` closes this gap with four subcommands:

- **`list`** — browse all entries with `--category`/`--session` filters and `--limit`/`--offset` pagination
- **`get`** — inspect a single entry by key (supports prefix match — no need to copy full UUID)
- **`stats`** — backend health, total count, per-category breakdown at a glance
- **`clear`** — batch delete by `--category`, single delete by `--key`, with confirmation prompt (`--yes` to skip)

| Before | After |
|--------|-------|
| Memory is a black box | `memory stats` shows health + distribution |
| Can't see what auto-save stored | `memory list --category conversation` |
| Can't inspect a specific entry | `memory get <key-or-prefix>` |
| Can't clean stale data without `/clear` in agent | `memory clear --category daily --yes` |
| Must enter agent loop to manage memory | Direct CLI, no LLM invocation needed |

| File | Change |
|------|--------|
| `src/memory/cli.rs` | **New** — CLI handler with list/get/stats/clear + unit tests |
| `src/memory/mod.rs` | Add `pub mod cli` |
| `src/lib.rs` | Add `MemoryCommands` public enum |
| `src/main.rs` | Add private `MemoryCommands`, `Commands::Memory` variant, match arm |

- **Lightweight backend creation**: CLI uses `create_memory_for_migration` (no embedding provider) since
list/get/stats/clear don't need vector search. Postgres handled separately.
- **Prefix matching**: Both `get` and `clear --key` fall back to prefix search when exact match fails — essential
since keys are UUIDs.
- **Confirmation by default**: All destructive operations require `dialoguer::Confirm`; `--yes` for
scripts/automation.
- **Record-style list output**: Full key displayed (no truncation), one entry per block — keys are too long for
  tabular layout.
2026-02-21 02:22:16 +08:00
Jakub Buzuk
951076e026 feat(service): add --config-dir flag and improve OpenRC setup
- Add global --config-dir CLI flag that sets ZEROCLAW_CONFIG_DIR env
- Add ZEROCLAW_CONFIG_DIR override in config resolution (takes precedence)
- Update OpenRC script to use --config-dir and set env vars for config/workspace
- Prefer /usr/local/bin/zeroclaw for OpenRC executable
- Create /etc/zeroclaw/workspace directory with correct ownership on install
- Update docs to reflect --service-init flag order (service-level before subcommand)
2026-02-20 23:30:55 +08:00
Jakub Buzuk
87fa033517 feat(service): add OpenRC support for Alpine Linux
- Add InitSystem enum with auto-detection (systemd/OpenRC)
- Add --service-init CLI flag to override init system detection
- Generate OpenRC init script with security hardening:
  - Runs as zeroclaw:zeroclaw user
  - umask 027 for file permissions
  - Logs to /var/log/zeroclaw/
  - Depends on net and firewall
- Require root for OpenRC install with clear error message
- Warn if binary is in home directory
- Add OpenRC auto-restart support in channels module
- Document OpenRC setup in README and network-deployment.md

Non-goals:
- No changes to systemd behavior
- No user-level OpenRC services
- No other init systems (SysV, runit, s6)

Security: OpenRC install requires root, validates user, creates
directories with proper permissions
2026-02-20 23:30:55 +08:00
Chummy
572cde695a feat(channel): add native nextcloud talk webhook integration 2026-02-20 23:28:18 +08:00
Chummy
5dbb909bc3 feat(cli): add stdout-safe shell completions command 2026-02-20 19:20:14 +08:00
Chummy
a2e9c0d1e1 fix(skills): make open-skills sync opt-in and configurable 2026-02-20 16:45:50 +08:00
Chummy
70f12e5df9 test(onboard): add regression coverage for quick setup model override 2026-02-20 16:22:03 +08:00
Chummy
db2d9acd22
fix(skills): support SSH git remotes for skills install (#1035) 2026-02-19 23:25:47 -05:00
Chummy
740eb17d76 fix(channel): hot-apply runtime config updates for running channel service 2026-02-20 11:05:41 +08:00
Alex Gorevski
b6f99c31d1
Merge pull request #982 from zeroclaw-labs/fix/cli-help-text-improvements
docs(cli): add detailed help text and examples to complex subcommands
2026-02-19 11:54:38 -08:00
Alex Gorevski
39a09f007b fix(cli): add range validation for temperature argument
Add a custom value_parser for the --temperature CLI argument to enforce
the documented 0.0-2.0 range at parse time. Previously, the comment
stated the valid range but clap did not reject out-of-range values,
allowing invalid temperatures to propagate to provider API calls.

- Add parse_temperature() validator that rejects values outside 0.0..=2.0
- Wire it into the Agent subcommand's temperature arg via value_parser

Addresses API surface audit §2.3 (CLI argument range validation).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-19 11:45:12 -08:00
Alex Gorevski
9f1a306962 docs(cli): add detailed help text and examples to complex subcommands
Add long_about attributes with usage examples to the following commands:

src/main.rs (binary CLI):
- Agent: interactive/single-message modes, provider/peripheral options
- Gateway: port/host binding with examples
- Daemon: full runtime explanation with service install reference
- Cron: cron expression format, timezone handling, all scheduling modes
- Channel: supported types, JSON config format, bind-telegram
- Hardware: discover, introspect, info subcommands
- Peripheral: add, flash, board types
- Config: schema export

src/lib.rs (library enums):
- CronCommands::Add: cron syntax and timezone examples
- CronCommands::AddAt: RFC 3339 timestamp format
- CronCommands::AddEvery: interval in milliseconds
- CronCommands::Once: human-readable duration syntax
- CronCommands::Update: partial field update
- ChannelCommands::Add: JSON config and supported types
- ChannelCommands::BindTelegram: username/numeric ID format
- HardwareCommands::Discover, Introspect, Info: device paths and chip names
- PeripheralCommands::Add: board types and transport paths
- PeripheralCommands::Flash: serial port options

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-19 11:42:31 -08:00
Chummy
dcd0bf641d feat: add multimodal image marker support with Ollama vision 2026-02-19 21:25:21 +08:00
Jayson Reis
f1ca73d3d2 chore: Remove more blocking io calls 2026-02-19 18:04:55 +08:00
cbigger
3c60b6bc2d feat(onboard): add optional --model flag to quick setup and channels-only guard 2026-02-19 17:36:20 +08:00
s04
282fbe0e95 style: fix cargo fmt formatting in config schema handler 2026-02-19 16:41:21 +08:00
s04
996f66b6a7 feat: add zeroclaw config schema for JSON Schema export
Add a `config schema` subcommand that dumps the full configuration
schema as JSON Schema (draft 2020-12) to stdout. This enables
downstream consumers (like PankoAgent) to programmatically validate
configs, generate forms, and stay in sync with zeroclaw's evolving
config surface without hand-maintaining copies of the schema.

- Add schemars 1.2 dependency and derive JsonSchema on all config
  structs/enums (schema.rs, policy.rs, email_channel.rs)
- Add `Config` subcommand group with `Schema` sub-command
- Output is valid JSON Schema with $defs for all 56 config types
2026-02-19 16:41:21 +08:00
Edvard
8b4607a1ef feat(cron): add cron update CLI subcommand for in-place job updates
Add Update variant to CronCommands in both main.rs and lib.rs, with
handler in cron/mod.rs that constructs a CronJobPatch and calls
update_job(). Includes security policy check for command changes.

Fixes from review feedback:
- --tz alone now correctly updates timezone (fetches existing schedule)
- --expression alone preserves existing timezone instead of clearing it
- All-None patch (no flags) now returns an error
- Output uses consistent emoji prefix

Tests exercise handle_command directly to cover schedule construction.

Closes #809

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 15:11:37 +08:00