Commit Graph

1622 Commits

Author SHA1 Message Date
argenis de la rosa
8144938ac5 feat(web): electric blue dashboard restyle with animations and logo
Restyle the entire web dashboard with an electric blue theme featuring
glassmorphism cards, smooth animations, and the ZeroClaw logo. Remove
duplicate Vite dev server infrastructure to ensure a single gateway.

- Add electric blue color palette and glassmorphism styling system
- Add 10+ keyframe animations (fade, slide, pulse-glow, shimmer, float)
- Restyle all 10 pages with glass cards and electric components
- Add ZeroClaw logo to sidebar, pairing screen, and favicon
- Remove Vite dev/preview scripts and proxy config (build-only now)
- Update pairing dialog with ambient glow and animated elements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:06:54 -04:00
argenis de la rosa
7e0570abd6 Merge remote-tracking branch 'origin/master' 2026-03-13 09:38:00 -04:00
Argenis
5d1543100d
fix: support Linq 2026-02-03 webhook payload shape (#3337) (#3410)
Closes #3337

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:31:53 -04:00
Argenis
e3a91bc805
fix: gate prometheus and fix AtomicU64 for 32-bit targets (#3409)
* fix: gate prometheus and fix AtomicU64 for 32-bit targets (#3335)

Closes #3335

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: fix import ordering for cfg-gated atomics

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:31:25 -04:00
Argenis
833fdefbe5
fix: restore MCP support missing from master branch (#3412)
MCP (Model Context Protocol) config and tool modules were added on the
old `main` branch but never made it to `master`. This restores the full
MCP subsystem: config schema, transport layer (stdio/HTTP/SSE), client
registry, tool wrapper, config validation, and channel wiring.

Closes #3379

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:20:37 -04:00
Argenis
13f74f0ecc
fix: restore web dashboard by auto-building frontend in build.rs (#3408)
The build.rs was reduced to only creating an empty web/dist/ directory,
which meant rust-embed would embed no files and the SPA fallback handler
would return 404 for every request including `/`. This is a regression
from v0.1.8 where web/dist/ was still tracked in git.

Update build.rs to detect when web/dist/index.html is missing and
automatically run `npm ci && npm run build` if npm is available. The
build is best-effort: when Node.js is absent the Rust build still
succeeds with an empty dist directory (release workflows pre-build the
frontend separately).

Closes #3386

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:20:34 -04:00
Argenis
9ff045d2e9
fix: resolve install.sh prebuilt download 404 by querying releases API (#3406)
The /releases/latest/download/ URL only resolves to the latest non-prerelease,
non-draft release. When that release has no binary assets (e.g. v0.1.9a),
--prebuilt-only fails with a 404. This adds resolve_asset_url() which queries
the GitHub releases API for the newest release (including prereleases) that
actually contains the requested asset, falling back to /releases/latest/ if
the API call fails.

Closes #3389

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:20:31 -04:00
Argenis
6fe8e3a5bb
fix: gracefully handle reasoning_enabled for unsupported Ollama models (#3411)
When reasoning_enabled is configured, the Ollama provider sends
think=true to all models. Models that don't support the think parameter
(e.g. qwen3.5:0.8b) cause request failures that the reliable provider
classifies as retryable, leading to an infinite retry loop.

Fix: when a request with think=true fails, automatically retry once
with think omitted. This lets the call succeed on models that lack
reasoning support while preserving thinking for capable models.

Closes #3183
Related #850

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:16:03 -04:00
Argenis
5dc1750df7
fix: add crypto.randomUUID fallback for older browsers (#3407)
Replace direct `crypto.randomUUID()` calls in the web dashboard with a
`generateUUID()` utility that falls back to a manual UUID v4 implementation
using `crypto.getRandomValues()` when `randomUUID` is unavailable (older
Safari, some Electron builds, Raspberry Pi browsers).

Closes #3303
Closes #3261

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:16:00 -04:00
argenis de la rosa
0931b140cf Merge origin/master into master
Made-with: Cursor
2026-03-13 09:08:46 -04:00
SimianAstronaut7
b40c9e77af
Merge pull request #3365 from zeroclaw-labs/ci/fix-glibc-cache-mismatch
ci: pin release workflows to ubuntu-latest to fix glibc cache mismatch
2026-03-12 17:44:42 -04:00
simianastronaut
34cac3d9dd ci: pin release workflows to ubuntu-latest to fix glibc cache mismatch
CI workflows use ubuntu-latest (24.04, glibc 2.39) while release
workflows used ubuntu-22.04 (glibc 2.35). Swatinem/rust-cache keys
on runner.os ("Linux"), not the specific version, so cached build
scripts compiled on 24.04 would fail on 22.04 with GLIBC_2.39 not
found errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:37:31 -04:00
SimianAstronaut7
badf96dcab
Merge pull request #3363 from zeroclaw-labs/ci/faster-apple-build
ci: use thin LTO profile for faster CI builds
2026-03-12 17:31:29 -04:00
simianastronaut
c1e1228fb0 ci: use thin LTO profile for faster CI builds
The release profile uses fat LTO + codegen-units=1, which is
optimal for distribution binaries but unnecessarily slow for CI
validation builds. Add a dedicated `ci` profile with thin LTO and
codegen-units=16, and use it in both CI workflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:18:36 -04:00
SimianAstronaut7
d2b923ae07
Merge pull request #3322 from zeroclaw-labs/work-issues/2984-fix-cli-chinese-input-crash
fix(agent): use byte-level stdin reads to prevent CJK input crash
2026-03-12 16:58:46 +00:00
SimianAstronaut7
21fdef95f4
Merge pull request #3324 from zeroclaw-labs/work-issues/2907-channel-send-message
feat(channel): add `channel send` CLI command for outbound messages
2026-03-12 16:58:44 +00:00
SimianAstronaut7
d02fbf2d76
Merge pull request #3326 from zeroclaw-labs/work-issues/2978-tool-call-dedup-exempt
feat(agent): add tool_call_dedup_exempt config to bypass within-turn dedup
2026-03-12 16:58:41 +00:00
SimianAstronaut7
05cede29a8
Merge pull request #3328 from zeroclaw-labs/fix/2926-configurable-provider-timeout
feat(provider): make HTTP request timeout configurable
2026-03-12 16:58:38 +00:00
SimianAstronaut7
d34a2e6d3f
Merge pull request #3329 from zeroclaw-labs/work-issues/2443-approval-manager-shadowed-binding
fix(channel): remove shadowed variable bindings in test functions
2026-03-12 16:58:35 +00:00
SimianAstronaut7
576d22fedd
Merge pull request #3330 from zeroclaw-labs/work-issues/2884-ws-token-query-param
fix(gateway): restore multi-source WebSocket auth token extraction
2026-03-12 16:58:32 +00:00
SimianAstronaut7
d5455c694c
Merge pull request #3332 from zeroclaw-labs/work-issues/2896-discord-ws-silent-stop
fix(channel): handle websocket Ping frames and read errors in Discord gateway
2026-03-12 16:58:30 +00:00
SimianAstronaut7
90275b057e
Merge pull request #3339 from zeroclaw-labs/work-issues/2880-fix-workspace-path-blocked
fix(security): allow absolute paths within workspace when workspace_only is set
2026-03-12 16:58:27 +00:00
SimianAstronaut7
d46b4f29d2
Merge pull request #3341 from zeroclaw-labs/work-issues/2403-telegram-photo-duplicate
fix(channel): prevent first-turn photo duplication in memory context
2026-03-12 16:58:23 +00:00
simianastronaut
f25835f98c fix(channel): prevent first-turn photo duplication in memory context (#2403)
When auto_save is enabled and a photo is sent on the first turn of a
Telegram session, the [IMAGE:] marker was duplicated because:

1. auto_save stores the photo message (including the marker) to memory
2. build_memory_context recalls the just-saved entry as relevant context
3. The recalled marker is prepended to the original message content

Fix: skip memory context entries containing [IMAGE:] markers in
should_skip_memory_context_entry so auto-saved photo messages are not
re-injected through memory context enrichment.

Closes #2403

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:03:29 -04:00
simianastronaut
376579f9fa fix(security): allow absolute paths within workspace when workspace_only is set (#2880)
When workspace_only=true, is_path_allowed() blanket-rejected all
absolute paths.  This blocked legitimate tool calls that referenced
files inside the workspace using an absolute path (e.g. saving a
screenshot to /home/user/.zeroclaw/workspace/images/example.png).

The fix checks whether an absolute path falls within workspace_dir or
any configured allowed_root before rejecting it, mirroring the priority
order already used by is_resolved_path_allowed().  Paths outside the
workspace and allowed roots are still blocked, and the forbidden-paths
list continues to apply to all other absolute paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:59:35 -04:00
simianastronaut
b620fd6bba fix(channel): handle websocket Ping frames and read errors in Discord gateway
The Discord gateway event loop silently dropped websocket Ping frames
(via a catch-all `_ => continue`) without responding with Pong. After
splitting the websocket stream into read/write halves, automatic
Ping/Pong handling is disabled, so the server-side (Cloudflare/Discord)
eventually considers the client unresponsive and stops sending events.

Additionally, websocket read errors (`Some(Err(_))`) were silently
swallowed by the same catch-all, preventing reconnection on transient
failures.

This patch:
- Responds to `Message::Ping` with `Message::Pong` to maintain the
  websocket keepalive contract
- Breaks the event loop on `Some(Err(_))` with a warning log, allowing
  the supervisor to reconnect

Closes #2896

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:15:53 -04:00
simianastronaut
98d6c5af9e fix(gateway): restore multi-source WebSocket auth token extraction (#2884)
The Electric Blue dashboard (PR #2804) sends the pairing token as a
?token= query parameter, but the WS handler only checked that single
source. Earlier PR #2193 had established a three-source precedence
chain (header > subprotocol > query param) which was lost.

Add extract_ws_token() with the documented precedence:
  1. Authorization: Bearer <token> header
  2. Sec-WebSocket-Protocol: bearer.<token> subprotocol
  3. ?token=<token> query parameter

This ensures browser-based clients (which cannot set custom headers)
can authenticate via query param or subprotocol, while non-browser
clients can use the standard Authorization header.

Includes 9 unit tests covering each source, precedence ordering,
and empty-value fallthrough.

Closes #2884

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:01:26 -04:00
simianastronaut
c51ca19dc1 fix(channel): remove shadowed variable bindings in test functions (#2443)
Rename shadowed `histories` and `store` bindings in three test functions
to eliminate variable shadows that are flagged under stricter lint
configurations (clippy::shadow_unrelated). The initial bindings are
consumed by struct initialization; the second bindings that lock the
mutex guard are now named distinctly (`locked_histories`, `cleanup_store`).

Closes #2443

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:00:31 -04:00
simianastronaut
ea6abc9f42 feat(provider): make HTTP request timeout configurable (#2926)
The provider HTTP request timeout was hardcoded at 120 seconds in
`OpenAiCompatibleProvider::http_client()`. This makes it configurable
via the `provider_timeout_secs` config key and the
`ZEROCLAW_PROVIDER_TIMEOUT_SECS` environment variable, defaulting
to 120s for backward compatibility.

Changes:
- Add `provider_timeout_secs` field to Config with serde default
- Add `ZEROCLAW_PROVIDER_TIMEOUT_SECS` env var override
- Add `timeout_secs` field and `with_timeout_secs()` builder on
  `OpenAiCompatibleProvider`
- Add `provider_timeout_secs` to `ProviderRuntimeOptions`
- Thread config value through agent loop, channels, gateway, and tools
- Use `compat()` closure in provider factory to apply timeout to all
  compatible providers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:40:18 -04:00
simianastronaut
e2f6f20bfb feat(agent): add tool_call_dedup_exempt config to bypass within-turn dedup (#2978)
Add `agent.tool_call_dedup_exempt` config key (list of tool names) to
allow specific tools to bypass the within-turn identical-signature
deduplication check in run_tool_call_loop. This fixes the browser
snapshot polling use case where repeated calls with identical arguments
are legitimate and should not be suppressed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:28:42 -04:00
simianastronaut
88df3d4b2e feat(channel): add channel send CLI command for outbound messages (#2907)
Add a `zeroclaw channel send` subcommand that sends a one-off message
through a configured channel without starting the full agent loop.
This enables hardware sensor triggers (e.g., range sensors on
Raspberry Pi) to push notifications to Telegram and other platforms.

Usage:
  zeroclaw channel send 'Alert!' --channel-id telegram --recipient <chat_id>

Supported channels: telegram, discord, slack.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:18:04 -04:00
simianastronaut
0dba55959d fix(agent): use byte-level stdin reads to prevent CJK input crash
When running through a PTY chain (kubectl exec, SSH, remote terminals),
the transport layer may split data frames at space (0x20) boundaries,
interrupting multi-byte UTF-8 characters mid-sequence. Rust's
BufRead::read_line requires valid UTF-8 and returns InvalidData
immediately, crashing the interactive agent loop.

Replace stdin().read_line() with byte-level read_until(b'\n') followed
by String::from_utf8_lossy() in both the main input loop and the
/clear confirmation prompt. This reads raw bytes without UTF-8
validation during transport, then does lossy conversion (replacing any
truly invalid bytes with U+FFFD instead of crashing).

Also set ENV LANG=C.UTF-8 in both Dockerfile stages as defense-in-depth
to ensure the container locale defaults to UTF-8.

Closes #2984

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:08:49 -04:00
SimianAstronaut7
893788f04d
fix(security): strip URLs before high-entropy token extraction (#3064) (#3321)
The credential leak detector's check_high_entropy_tokens would
false-positive on URL path segments (e.g. long alphanumeric filenames)
because extract_candidate_tokens included '/' in the token character
set, creating long mixed-alpha-digit tokens that exceeded the Shannon
entropy threshold.

Fix: strip URLs from content before extracting candidate tokens for
entropy analysis. Structural pattern checks (API keys, JWTs, AWS
credentials) use dedicated regexes and are unaffected.

Closes #3064

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:53:38 +00:00
SimianAstronaut7
0fea62d114
fix(tool): resolve Brave API key lazily with decryption support (#3078) (#3320)
WebSearchTool previously stored the Brave API key once at boot and never
re-read it. This caused three failures: (1) keys set after boot via
web_search_config were ignored, (2) encrypted keys passed as raw enc2:
blobs to the Brave API, and (3) keys absent at startup left the tool
permanently broken.

The fix adds lazy key resolution at execution time. A fast path returns
the boot-time key when it is plaintext and non-empty. When the boot key
is missing or still encrypted, the tool re-reads config.toml, decrypts
the value through SecretStore, and uses the result. This also means
runtime config updates (e.g. `web_search_config set brave_api_key=...`)
are picked up on the next search invocation.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:53:35 +00:00
SimianAstronaut7
cca3cf8f84
fix(agent): use char-boundary-safe slicing in scrub_credentials (#3024) (#3319)
Replace byte-level `&val[..4]` slice with `char_indices().nth(4)` to
prevent a panic when the captured credential value contains multi-byte
UTF-8 characters (e.g. Chinese text).  Adds a regression test with
CJK input.

Closes #3024

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:53:32 +00:00
SimianAstronaut7
7170810e98
fix(channel): drop MutexGuard before .await in WhatsApp Web listen (#3315)
Extract `self.bot_handle.lock().take()` into a separate `let` binding
so the parking_lot::MutexGuard is dropped before the `.await`, making
the listen future Send again.

Closes #3312

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:16:40 +00:00
SimianAstronaut7
816fa87d60
fix(channel): restore Lark/Feishu channel compilation (#3318)
Replace the `use_feishu: bool` field on `LarkChannel` with a
`platform: LarkPlatform` enum field, add `mention_only` to the
`new_with_platform` constructor, and introduce `from_lark_config` /
`from_feishu_config` factory methods so the channel factory in
`mod.rs` and the existing tests compile.

Resolves #3302

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:16:31 +00:00
Argenis
dcffa4d7fb
fix(ci): add missing ci-run.yml workflow (#3268)
The ci-run.yml workflow was referenced in docs/contributing/ci-map.md
and branch protection rules but never existed in the repository,
causing push-triggered CI runs to fail immediately with zero jobs
and no logs.

This adds the workflow with all documented jobs: lint, strict delta
lint, test, build (linux + macOS), docs quality, and the CI Required
Gate composite check. Triggers on both push and pull_request to master.

Fixes #2853

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:48:16 +00:00
Argenis
e03dc4bfce
fix(security): unify cron shell validation across API/CLI/scheduler (#3270)
Centralize cron shell command validation so all entrypoints enforce the
same security policy (allowlist + risk gate + approval) before
persistence and execution.

Changes:
- Add validate_shell_command() and validate_shell_command_with_security()
  as the single validation gate for all cron shell paths
- Add add_shell_job_with_approval() and update_shell_job_with_approval()
  that validate before persisting
- Add add_once_validated() and add_once_at_validated() for one-shot jobs
- Make raw add_shell_job/add_job/add_once/add_once_at pub(crate) to
  prevent unvalidated writes from outside the cron module
- Route gateway API through validated creation path
- Route schedule tool through validated helpers (single validation)
- Route cron_add/cron_update tools through validated helpers
- Unify scheduler execution validation via validate_shell_command_with_security
- CLI update handler uses full validate_command_execution instead of
  just is_command_allowed
- Add focused tests for validation parity across entrypoints
- Standardize error format to "blocked by security policy: {reason}"

Closes #2741
Closes #2742

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:48:13 +00:00
Darren.Zeng
2cb57e6b2d
fix(cli): honor config default_temperature in agent command (#3106)
* fix(cli): honor config default_temperature in agent command

Fixes #3033

The agent command was using a hardcoded default_value of 0.7 for the
--temperature parameter, which ignored the default_temperature setting
in the config file.

Changes:
- Changed temperature from f64 to Option<f64>
- Removed hardcoded default_value
- Use config.default_temperature when --temperature is not provided

Users can now set default_temperature in config.toml and have it
honored when running 'zeroclaw agent' without --temperature.

Risk: low (behavior change: now honors config instead of hardcoded value)

* fix: resolve moved value error for config in agent command

Extract final_temperature before passing config to agent::run() to
avoid use-of-moved-value error (config is moved as the first argument
while config.default_temperature was being accessed in the same call).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:34:32 -04:00
Alix-007
079e972c81
fix(release): use master in cut_release_tag helper (#3249)
Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:20:36 -04:00
Argenis
448682c440
feat(providers): add Azure OpenAI provider support (#3246)
Closes #3176
2026-03-12 00:06:11 -04:00
Argenis
3fe3fe23b1
feat(build): add 32-bit system support via feature gates (#3245)
Closes #3174
2026-03-12 00:06:08 -04:00
Alix-007
9e9052634d
fix(ci): use master merge-base in collect_changed_links (#3250)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:45:36 -04:00
Alix-007
b227b1abc3
fix(docs): correct default branch in triage snapshot (#3253)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:45:34 -04:00
Alix-007
fb9501afd5
fix(install): guard empty docker namespace args on Bash 3.2 (#3248)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:43:21 -04:00
Alix-007
9df0a76f4a
fix(ci): use master merge-base in docs_quality_gate (#3251)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:43:19 -04:00
Alix-007
9501555448
fix(ci): use master merge-base in rust_strict_delta_gate (#3252)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:43:16 -04:00
Alix-007
138ada0fd6
fix(release): lower GNU Linux build runner baseline (#3257)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 23:43:14 -04:00
Darren.Zeng
3c2c5aa78c
feat(web): add auto-expanding multiline chat composer (#3185)
* feat(web): add auto-expanding multiline chat composer

Convert chat input from single-line input to auto-expanding textarea:

- Replace input with textarea for multiline support
- Add auto-resize logic that grows up to max height (200px)
- Enter sends message, Shift+Enter adds new line
- Reset height after sending message
- Add overflow-y-auto for scrolling when max height reached
- Update placeholder to indicate Shift+Enter for new line

Fixes #3119

* fix: run cargo fmt to fix lint CI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: trigger CI re-run

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:35:38 -04:00