Commit Graph

173 Commits

Author SHA1 Message Date
nyk d0cd8701c7
feat: add Dunk It button animation with CSS transitions (#427)
Add a CSS-only Dunk It button to task cards with a 4-phase state
machine (idle, success, error, dismissing). Uses inline CSS
transitions for animations with no external dependencies.

Supersedes #373
2026-03-17 13:52:34 +07:00
nyk 2f2531f3d1
feat: discover and display per-agent workspace skill roots (#426)
Dynamically scan workspace-* directories under the openclaw state dir
to discover per-agent skill roots. Display them in the Skills Hub with
agent-specific labels and violet badge styling.

Closes #412
Supersedes #413
2026-03-17 13:52:27 +07:00
nyk 4671946e97
fix: remove CSP nonce from style-src to unblock reagraph canvas (#425)
Replace style-src nonce directive with unsafe-inline to support
reagraph's runtime <style> injection. Add style-src-elem and
style-src-attr directives for CSP Level 3 compliance. Extend
fitNodesInView retries from 2 to 4 for more reliable canvas sizing.

Closes #414
Supersedes #415
2026-03-17 13:52:09 +07:00
Brixyy b908c40ba5
fix: add workspace skill root to skill-sync.ts (#411)
Fixes #410 — getSkillRoots() in skill-sync.ts was not updated when #408 added workspace support to route.ts, causing the scheduler sync to never populate workspace skills (always showing 0).
2026-03-16 22:24:31 +07:00
nyk 6f1237704a
feat: add workspace skill root and root-based filtering to Skills Hub (#408)
- Add `workspace` skill root (~/.openclaw/workspace/skills) for
  workspace-local skill discovery alongside the existing 5 roots
- Make group cards clickable to filter the installed skills list by root
- Add `workspace` as valid target for skill creation and registry install
- Add `showAllRoots` i18n key to all 10 locale files

Closes #364
2026-03-16 12:37:51 +07:00
nyk 17bf0761f5
fix: migrate clawdbot CLI calls to gateway RPC and improve session labels (#407)
Replace all `runClawdbot(['-c', ...])` invocations with
`callOpenClawGateway()` RPC calls in session control, spawn, and delete
routes. This eliminates the deprecated CLI dependency and uses the
structured gateway protocol instead.

Also add `formatSessionLabel()` helper and `useAgentSessions()` hook to
task-board-panel for better session dropdown display labels.

Closes #401, closes #406
2026-03-16 12:18:12 +07:00
nyk 85b4184aa9
feat: GNAP sync engine for git-native task persistence (#396)
Implements Phase 1 of GNAP (Git-Native Agent Protocol) integration:
- SQLite stays primary, GNAP repo is an optional sync target
- Push task create/update/delete to .gnap/tasks/{id}.json with git commits
- Status/priority mapping between MC and GNAP formats
- Management API at /api/gnap (status, init, manual sync)
- GNAP badge in task board header with click-to-sync
- 15 unit tests covering mapping, init, push, remove, pull, and status

Enable with GNAP_ENABLED=true in .env. Follows the same fire-and-forget
pattern as the existing GitHub sync engine.

Closes #374
Supersedes #389
2026-03-16 12:07:39 +07:00
nyk d87307a4f8
feat: hybrid mode — show gateway + local sessions simultaneously (#392)
Always merge both gateway and local (Claude Code, Codex, Hermes) sessions
in the sessions API instead of gating on `include_local`. The conversation
list now renders all sources unconditionally, using each session's `source`
field for display logic rather than the global `dashboardMode`.

- Add `localSessionsAvailable` store flag, set from capabilities `claudeHome`
- Remove `include_local` query param and early-return in sessions API
- Remove source-based filter and `dashboardMode` branching in conversation list
- Show both gateway and local active/recent groups when data exists
2026-03-16 12:05:41 +07:00
HonzysClawdbot 301ee9cdd8
fix(gateway): probe /api/health instead of root URL (#394)
* fix(gateway): probe /api/health instead of root URL for health checks (#390)

The server-side gateway health probe was fetching the root URL (/)
which returns HTTP 400 on OpenClaw 2026.3.13 gateways. The gateway
exposes a dedicated /api/health endpoint that returns 200 with status
info.

The WebSocket ping RPC 'unknown method' issue is already handled —
websocket.ts detects the INVALID_REQUEST and falls back to passive
heartbeat mode. The actual bug was this HTTP probe hitting the wrong
endpoint.

Fixes #390

* fix(gateway): ensure gateways table exists before health probe

The gateways table is created lazily by the gateways API (ensureTable).
The health route was querying it directly without CREATE IF NOT EXISTS,
causing SqliteError: no such table: gateways in fresh databases (E2E tests,
Docker first-boot).

Add ensureGatewaysTable() inline to mirror the pattern in route.ts.

* fix: update health-utils test to match /api/health probe path

The test file has its own copy of buildGatewayProbeUrl — update it to
append /api/health instead of / to match the route.ts change.

---------

Co-authored-by: Nyk <0xnykcd@googlemail.com>
2026-03-16 11:55:56 +07:00
HonzysClawdbot 0acf7daf32
feat: task assignment session targeting (#399)
* feat: add task session targeting - dispatch tasks to specific agent sessions (#395)

When assigning a task to an agent, users can now optionally select an
existing session to dispatch the task to instead of creating a new one.

Changes:
- task-dispatch.ts: When target_session is set in task metadata, use
  gateway chat.send to dispatch to that specific session instead of
  creating a new one via call agent
- task-board-panel.tsx: Add session selector dropdown in both Create
  and Edit task modals that appears when an agent is selected and has
  active sessions
- store/index.ts: Add agent and channel fields to Session interface

Closes #395

* fix(gateway): ensure gateways table exists before health probe

The gateways table is created lazily by the gateways API (ensureTable).
The health route was querying it directly without CREATE IF NOT EXISTS,
causing SqliteError: no such table: gateways in fresh databases (E2E tests,
Docker first-boot).

Add ensureGatewaysTable() inline to mirror the pattern in route.ts.
2026-03-16 11:34:28 +07:00
nyk e7aa7e6a91
fix: reduce server memory footprint (#405)
* fix: reduce server memory footprint across session parsing, caching, and rate limiting

- Stream-parse Claude JSONL session files instead of loading entire files into memory
- Add 50MB file size cap to skip oversized session transcripts
- Add 30s TTL cache to getAllGatewaySessions() to avoid redundant disk reads per scheduler tick
- Cap rate limiter maps at 10,000 entries with oldest-first eviction
- Add request.signal abort listener to SSE route for defense-in-depth cleanup
- Add test for rate limiter maxEntries eviction behavior

* fix: address audit findings across all memory-fix files

claude-sessions.ts:
- Wrap readline loop in try/finally to ensure rl.close() on error paths
- Guard statSync in file loop to handle files deleted between readdir and stat
- Fix variable shadowing: rename inner `now` to `nowSec` to avoid confusion
- Update throttle timestamp on empty scan results (prevents repeated disk scans)
- Skip sidechain-only sessions (zero user+assistant messages)

sessions.ts:
- Decouple `active` flag from cache — compute at read time to prevent stale data
- Remove activeWithinMs from cache key to eliminate cache thrashing between
  callers using different windows (Infinity vs default)
- Add invalidateSessionCache() and call it after pruneGatewaySessionsOlderThan

events/route.ts:
- Null out cleanup after first call to prevent double-invoke
- Remove unnecessary `if (request.signal)` guard (always defined on NextRequest)

rate-limit.test.ts:
- Rewrite eviction test with maxRequests=1 to actually prove eviction occurred
- Add assertion that non-evicted entries remain tracked
2026-03-16 11:30:02 +07:00
HonzysClawdbot b6717b8bf8
fix: remove duplicate task title constraint, improve delete handling and scrolling (#386)
- Remove duplicate title check from POST /api/tasks (closes #368)\n- Scope recurring tasks duplicate check by project_id\n- Fix task deletion error handling — show errors to user (closes #369)\n- Enable vertical scrolling on Kanban board (closes #376)\n- Refactor nodes route to use RPC via callOpenClawGateway\n- Handle read-only filesystem in gateway config registration\n- Add screenshot-drift CI workflow and guide\n- Docker compose: add host-gateway for reaching host gateway
2026-03-15 18:31:15 +07:00
Héctor Arriola d980fc1a4e
fix: use gateway call agent for notification delivery (#381)
Switches notification delivery from sessions_send to gateway call agent command. No longer requires session_key — uses agent name (recipient) directly. Timeout increased 10s to 30s.
2026-03-15 18:31:05 +07:00
Brixyy 8d671cb782
fix: scope memory health diagnostics to allowed prefixes (#367)
When memoryAllowedPrefixes is configured, scan only those subdirectories instead of the entire MEMORY_PATH. Falls back to full scan if no prefixes are set.\n\nCloses #366
2026-03-15 18:30:46 +07:00
Héctor Arriola d89183ee48
fix: fetch notifications immediately when recipient changes (#380)
Notifications were stale until the next poll after switching recipients. Now fetchNotifications() is called immediately on recipient change.
2026-03-15 18:29:21 +07:00
nyk 2449363868
fix: stop forcing dangerouslyDisableDeviceAuth + fix exec security value
- Remove unconditional `dangerouslyDisableDeviceAuth = true` from MC
  origin registration. MC should only add its origin to allowedOrigins,
  not silently downgrade the gateway's device auth security posture.

- Replace invalid `sandbox` value with `allowlist` in security scan
  and auto-fix for `tools.exec.security`. Current OpenClaw validates
  only: deny, allowlist, full. The old `sandbox` value was rejected.

Closes #357, closes #356
2026-03-14 21:44:11 +07:00
nyk 065d9f4082
fix: docker compose pids location + clear stale update banner
- Move pids limit from service-level `pids_limit` to
  `deploy.resources.limits.pids` for Compose v5+ compatibility.
  Some Compose versions normalize both into the same field, causing
  "can't set distinct values" errors.

- Clear OpenClaw update banner when `/api/openclaw/version` reports
  `updateAvailable: false`. Previously the banner could persist after
  a successful update because only the `true` path was handled.

Closes #353, closes #351
2026-03-14 21:03:02 +07:00
Brixyy e2ddf09a72
fix: unify GitHub sync token resolution with integrations env file 2026-03-14 20:46:29 +07:00
nyk 8386cfbec0
feat(tasks): classify task complexity and route to appropriate model tier
Co-authored-by: tomwattsca <17442606+tomwattsca@users.noreply.github.com>
2026-03-14 16:51:11 +07:00
HonzysClawdbot 2fe7785433
test: add gateway health history e2e + utility unit tests
* fix: show all agents in command select, disable those without active session

Previously the agent select in the OrchestrationBar only listed agents
with a session_key set (agents.filter(a => a.session_key)), causing the
dropdown to appear completely empty when agents exist but none have an
active session. This was confusing — users thought no agents were
registered.

Fix: show all registered agents in the dropdown. Agents without an
active session_key are shown as disabled with a '— no session' suffix
and a tooltip explaining why they can't be messaged. The 'No agents
registered' placeholder is shown only when the agents array is truly
empty.

The send button remains correctly disabled when no valid agent is
selected.

Fixes #321

* test: add gateway health history e2e + utility unit tests

- Add tests/gateway-health-history.spec.ts: Playwright e2e tests for
  GET /api/gateways/health/history and POST /api/gateways/health
  covering auth guards, response shape validation, chronological
  ordering, and gateway name resolution.

- Add src/app/api/gateways/health/health-utils.test.ts: 30 vitest
  unit tests for the pure utility functions in the health probe route:
  ipv4InCidr, isBlockedUrl (SSRF protection), buildGatewayProbeUrl,
  parseGatewayVersion, and hasOpenClaw32ToolsProfileRisk.

All 30 unit tests pass. Covers the health history feature introduced
in feat(gateways): add health history logging and timeline (#300).
2026-03-14 16:39:02 +07:00
Tom Watts 5d7b05b4f6
fix(tasks): use --expect-final for agent dispatch and Aegis review
The two-step agent → agent.wait pattern used in dispatchAssignedTasks and
runAegisReviews only returns lifecycle metadata (runId, status, timestamps).
The agent's actual response text is only available via --expect-final on the
initial agent call, which blocks until completion and returns the full payload
including result.payloads[0].text.

Without this fix:
- Task resolution is stored as the raw wait JSON instead of the agent's response
- Aegis cannot parse a VERDICT from the resolution, so it always defaults to rejected
- Tasks are permanently stuck in a reject/retry loop and never complete

Fix: replace the two-call pattern with a single --expect-final call in both
dispatchAssignedTasks and runAegisReviews. Also improve sessionId extraction
to use the agentMeta path from the final payload.

Co-authored-by: Tom Watts <tom@techteamup.com>
2026-03-14 16:38:55 +07:00
HonzysClawdbot 4fa1cbd3a5
fix: show all agents in command select, disable those without active session
Previously the agent select in the OrchestrationBar only listed agents
with a session_key set (agents.filter(a => a.session_key)), causing the
dropdown to appear completely empty when agents exist but none have an
active session. This was confusing — users thought no agents were
registered.

Fix: show all registered agents in the dropdown. Agents without an
active session_key are shown as disabled with a '— no session' suffix
and a tooltip explaining why they can't be messaged. The 'No agents
registered' placeholder is shown only when the agents array is truly
empty.

The send button remains correctly disabled when no valid agent is
selected.

Fixes #321
2026-03-14 16:38:53 +07:00
nyk 176e862431
fix(ui): improve agent panel empty state with discovery hints (#348)
Replace the unhelpful "POST /api/agents with X-Api-Key header" message
with a user-friendly hint explaining that agents are auto-discovered
from Claude, Codex, and Hermes directories, and that gateway mode shows
registered agents.

Adds missing noAgentsHint translation key across all 10 locales.

Closes #321
2026-03-14 16:29:24 +07:00
nyk 466a1621d4
fix: cron panel crash on missing schedule + doctor parser false positive (#347)
- Filter out cron jobs with missing/empty schedule before processing,
  preventing TypeError on .toLowerCase() (#342)
- Add defensive .localeCompare() guard in sort comparator
- Exclude positive/instructional lines ("No ... warnings detected",
  "Run: ...") from doctor issue extraction (#331)
- Strip negated warning phrases before keyword detection so "No channel
  security warnings detected" doesn't trigger warning level
- Add 2 tests for the doctor parser fix
2026-03-14 16:21:04 +07:00
HonzysClawdbot 8706147f84
fix(gateway): resolve Docker connectivity — 404 endpoints, EROFS write, missing OPENCLAW_HOME (#343)
* docs: add screenshot drift prevention guide and CI workflow

- Add docs/SCREENSHOT-GUIDE.md with step-by-step instructions for
  capturing, optimising, and committing fresh README screenshots
- Add .github/workflows/screenshot-drift.yml that detects UI file
  changes in PRs, applies a 'screenshot-drift' label, and posts a
  checklist comment reminding contributors to verify screenshots

Addresses: README screenshots may drift as the UI evolves quickly
(setup wizard, health history timeline, and onboarding were added
after the last screenshot refresh on 2026-03-11)

* fix(gateway): resolve Docker connectivity — 404 endpoints, EROFS write, missing OPENCLAW_HOME

Fixes #332, #333

Root causes
-----------
1. nodes/route.ts called non-existent HTTP REST endpoints on the gateway
   (/api/presence, /api/devices, /api/rpc). The OpenClaw gateway only
   exposes HTTP at /health; all other operations use WebSocket RPC.

2. gateway-runtime.ts attempted fs.writeFileSync on openclaw.json which
   fails with EROFS when the container or mount is read-only (docker-compose
   uses read_only: true by default).

3. install.sh never wrote the detected OPENCLAW_HOME or Docker host gateway
   IP into .env, leaving OPENCLAW_HOME empty after a fresh install.

Fixes
-----
- nodes/route.ts: replace HTTP calls to /api/presence and /api/devices
  with gateway /health reachability check + callOpenClawGateway() RPC
  (node.list / device.pair.list). When the openclaw CLI is unavailable
  inside Docker, the RPC falls back gracefully and returns connected=true
  with an empty list rather than a misleading 'Gateway offline' error.
  POST device actions likewise use callOpenClawGateway instead of /api/rpc.

- gateway-runtime.ts: catch EROFS / EACCES / EPERM on config write and
  emit a warn-level log with a hint, instead of an error. This eliminates
  the 'Failed to register MC in gateway config EROFS: read-only file
  system' log spam on Docker installs where openclaw.json is read-only.

- install.sh: after generating .env, write the detected OPENCLAW_HOME.
  In --docker mode also detect the Docker host IP (host-gateway or bridge
  default) and set OPENCLAW_GATEWAY_HOST so the container can reach a
  gateway running on the host out of the box.

- docker-compose.yml: add extra_hosts host-gateway so the container can
  resolve the Docker host IP; add a commented volume snippet for mounting
  the OpenClaw state directory read-only.
2026-03-14 15:38:13 +07:00
HonzysClawdbot 2b4438b63a
test: add coverage for pure utility modules, fix Vitest 60% threshold (#339)
* fix(db): add busy_timeout pragma and guard build-phase eager init

- Add busy_timeout = 5000 pragma to prevent SQLITE_BUSY errors under
  concurrent Next.js route-handler requests (WAL mode helps but is not
  sufficient without a retry budget).
- Guard module-level getDatabase() call with !isBuildPhase to prevent
  build-time vs runtime SQLite state conflicts on cold starts.
- Add tests covering both pragmas and build-phase skip behaviour.

* security(skill-registry): add path traversal and SSRF detection rules

- Add 'path-traversal' rule: detects ../../ and URL-encoded variants
- Add 'ssrf-internal-network' rule: detects fetch/curl/wget/axios targeting
  localhost, 127.x, 0.0.0.0, RFC-1918 private ranges, and *.internal hosts
- Add 'ssrf-metadata-endpoint' rule: detects access to cloud metadata
  endpoints (AWS 169.254.169.254, GCP metadata.google.internal)
- Add 14 new tests covering all new rules including edge cases

Closes #security-completeness

* test: add coverage for pure utility modules, fix 60% threshold

- Add tests for schedule-parser (parseNaturalSchedule, isCronDue): 34 tests
- Add tests for github-label-map (status/priority label bidirectional mapping): 18 tests
- Add tests for models (MODEL_CATALOG, getModelByAlias/Name, getAllModels): 8 tests
- Add tests for themes (THEMES, THEME_IDS, isThemeDark): 8 tests
- Add tests for paths (resolveWithin path traversal guard): 9 tests
- Add tests for password (hashPassword, verifyPassword): 11 tests
- Add tests for mentions (parseMentions): 12 tests
- Update vitest.config.ts coverage exclude list to focus on testable utility
  code rather than server-side orchestration modules (DB, WebSocket, etc.)
- Install @vitest/coverage-v8@2.1.9 matching vitest version
- Total: 616 tests passing, coverage 86% (up from 24% / below threshold)

Closes: Vitest 60% coverage threshold not met (builderz-labs backlog)
2026-03-14 15:38:11 +07:00
HonzysClawdbot 0cd85446c1
fix(db): add busy_timeout pragma and guard build-phase eager init (#337)
- Add busy_timeout = 5000 pragma to prevent SQLITE_BUSY errors under
  concurrent Next.js route-handler requests (WAL mode helps but is not
  sufficient without a retry budget).
- Guard module-level getDatabase() call with !isBuildPhase to prevent
  build-time vs runtime SQLite state conflicts on cold starts.
- Add tests covering both pragmas and build-phase skip behaviour.
2026-03-14 14:32:37 +07:00
firefloc-nox 8cf3b937eb
fix(onboarding): use POST for gateway health check in wizard (#334)
The test connection button in the onboarding wizard was using GET to
call /api/gateways/health, which only exports POST — resulting in a
405 and "Gateway unreachable" shown to the user.

Fixes the HTTP method to POST so the health probe works correctly.

Co-authored-by: Firefloc <firefloc@MacBook-Pro-de-Firefloc.local>
2026-03-14 14:32:33 +07:00
Clint Baxley ab7038af30
feat(gateway): detect port-based Tailscale Serve proxies (#330)
The existing Tailscale Serve detection only looked for a /gw path handler,
missing configurations where the gateway is proxied on a separate port
(e.g. :8443 → localhost:18789). This caused remote browsers to attempt
direct wss connections to the gateway port, which fails through Tailscale.

Extract Tailscale Serve detection into src/lib/tailscale-serve.ts and
extend it to discover port-based proxy mappings from the Tailscale Serve
JSON config. Also adds the macOS app bundle path for the Tailscale CLI
binary, which is not on PATH when installed via the Mac App Store.
2026-03-14 14:32:32 +07:00
jonboirama b5d44df705
fix: prefer explicit public gateway websocket url (#325) 2026-03-14 14:32:28 +07:00
nyk 863c100e66
feat: full i18n — 1752 keys across 10 languages, all panels translated (#326)
* feat: add i18n with 10 languages (en, zh, ja, ko, es, fr, de, pt, ru, ar)

Add internationalization infrastructure using next-intl with cookie-based
locale detection (NEXT_LOCALE cookie -> Accept-Language header -> default).

- Install next-intl and wire into Next.js config + root layout
- Create translation files for 10 languages covering auth pages,
  navigation labels, common UI strings, and settings
- Translate login page, setup page, and nav-rail labels
- Add LanguageSwitcher component (compact dropdown) to login page,
  setup page, nav-rail sidebar, and settings panel
- Support RTL layout for Arabic (dir="rtl" on html element)
- No URL-based locale routing — uses cookie-only approach to avoid
  breaking existing URLs and the custom proxy middleware

Panel internals are left with English strings for incremental
translation in follow-up PRs.

Based on the approach from PR #312 by richard-able, expanded to
10 languages with proper infrastructure.

* test(e2e): add i18n language switcher Playwright tests

Tests verify English default, all 10 language options, Chinese/Spanish
translations, cookie persistence across reload, and round-trip switching.

* test(e2e): fix i18n language switcher tests for cookie-based reload

Use direct cookie injection + page.goto instead of selectOption to
avoid race conditions with window.location.reload(). Fix Spanish
translation text to match actual es.json content.

* feat: complete full-app i18n — all components translated to 10 languages

Wire useTranslations() across 13 components with 293 keys in 12 namespaces:
- Boot loader: step labels, title, tagline
- Main page: skip-link, footer, full/local mode nudges
- Header bar: search, command palette, mode badge, SSE badge, tooltips
- Banners: local-mode, update, openclaw-update, openclaw-doctor
- Live feed: header, empty states, session labels
- Nav rail: context switcher, interface toggle, org section
- Onboarding wizard: all 4 steps (welcome, interface, gateway, credentials)
- Error boundary: extracted functional component for hook support

All 10 languages fully translated (en, zh, ja, ko, es, fr, de, pt, ru, ar)
with ICU plural format and proper per-language plural rules.

* feat(i18n): translate all panels and redesign language switcher

- Internationalize all 38 panel components with useTranslations()
- Expand translation keys from 293 to 1752 across 45 namespaces
- All 10 languages: en, zh, ja, ko, es, fr, de, pt, ru, ar
- Redesign language switcher: popover dropdown in header bar
  (replaces native <select> in sidebar)
- Keep LanguageSwitcherSelect for login, setup, and settings pages
- Fix github-sync-panel to use t.rich() for JSX interpolation
2026-03-14 14:27:25 +07:00
nyk 23204612eb
fix(ui): null-safe trim calls in agent model config (#329)
* fix(ui): null-safe trim calls in agent model config (#319)

Guard against undefined values in .trim() calls when editing agent
model configuration (primary model and fallback array entries).

Closes #319

* test: add unit tests for null-safe trim in agent model config

Tests verify that undefined/null values in model primary and fallback
arrays don't cause trim() TypeError crashes.

* test(e2e): add agent model config edge case tests

Tests verify PUT /api/agents/:id with valid config, empty fallbacks,
empty primary, and whitespace-only fallback entries.
2026-03-14 14:18:03 +07:00
nyk acd7ed8ba3
fix(ui): persist doctor banner dismiss with 24h expiry (#328)
* fix(ui): persist doctor banner dismiss with 24h expiry (#320)

Replace ephemeral useState dismiss with Zustand store + localStorage.
Banner stays hidden for 24 hours after dismiss, then resurfaces so
users can re-check. Mirrors the existing UpdateBanner pattern.

Closes #320

* test: add unit tests for doctor banner dismiss persistence

Tests verify localStorage persistence, 24h expiry, page refresh
survival, and graceful handling of corrupted values.
2026-03-14 14:18:00 +07:00
nyk 5208a76b76
fix(docker): Compose v5 pids_limit + copy public assets (#327)
* fix(docker): move pids to service-level pids_limit and copy public assets

- Move `pids: 256` from `deploy.resources.limits` to service-level
  `pids_limit` for Docker Compose v5+ compatibility (#322)
- Add `COPY --from=build /app/public ./public` to Dockerfile runtime
  stage so static assets (logos, icons) are available at runtime (#323)

Closes #322, closes #323

* test: add Docker config validation tests

Verifies pids_limit is at service level (Compose v5+), public dir
is copied in Dockerfile, and all required COPY instructions exist.
2026-03-14 14:17:57 +07:00
Nyk 2802f53d53 feat: add first-time setup wizard and zero-config startup
Eliminate friction for new users by adding a web-based setup wizard,
auto-generating infrastructure secrets, and providing actionable
feedback when no admin account exists.

- Add /setup page with visual progress steps for admin account creation
- Add /api/setup route (GET: check status, POST: create admin + auto-login)
- Auto-generate AUTH_SECRET and API_KEY when not set (persisted to .data/)
- Add docker-entrypoint.sh for zero-config Docker startup
- Login page auto-redirects to /setup when no users exist
- Login API returns NO_USERS error code with setup guidance
- Remove insecure defaults from .env.example
- Update README Quick Start for zero-config Docker and web setup
- Add CLAUDE.md for AI agent discoverability
2026-03-13 14:09:44 +07:00
Nyk d53d93351c fix(tasks): use gateway agent ID instead of display name for dispatch
Task dispatch and Aegis review were sending `agents.name` (the display
name) as `agentId` to the gateway. When `identity.name` differs from
the gateway agent `id`, the gateway rejects the call with
"unknown agent id".

Now extracts `openclawId` from the agent's config JSON (set during
agent sync) and uses that for gateway invocations, falling back to
the display name for backwards compatibility.

Closes #310
2026-03-13 12:32:25 +07:00
nyk 626c8fabff
Merge pull request #313 from builderz-labs/fix/http-tailscale-login
fix(auth): fix HTTP/Tailscale login — opt-in HTTPS redirect, CSP nonce propagation
2026-03-13 12:29:58 +07:00
Nyk a6e6341e23 fix(auth): fix HTTP/Tailscale login — opt-in HTTPS redirect, CSP nonce propagation
- Replace unconditional HTTP→HTTPS redirect with opt-in via NEXT_PUBLIC_FORCE_HTTPS=1
- Propagate CSP nonce into forwarded request headers so SSR inline scripts get the nonce
- Bind nonce attribute to layout's inline theme script to prevent CSP violations
- Extract CSP and browser-security helpers into dedicated modules with tests

Closes #308, #309, #311
2026-03-13 12:18:24 +07:00
dk-blackfuel cc8fc841a1
feat(auth): add trusted reverse proxy / header authentication (#306)
Adds MC_PROXY_AUTH_HEADER env var. When configured, getUserFromRequest
reads the named header for the authenticated username and resolves (or
optionally auto-provisions) the MC user without requiring a password.

This enables SSO via a trusted gateway such as Envoy OIDC — the gateway
injects preferred_username as a header from the validated JWT claim, and
MC maps it to an existing user, skipping the local login form entirely.

New env vars:
  MC_PROXY_AUTH_HEADER        — header name to read username from
  MC_PROXY_AUTH_DEFAULT_ROLE  — role for auto-provisioned users (optional)

Auto-provisioned users receive a random unusable password so they cannot
bypass the proxy and log in locally.

Closes #305

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 22:14:53 +07:00
nyk eddfd752c2
fix(auth): allow login on fresh HTTP Docker installs (#304)
* fix(auth): allow login cookies on HTTP docker deployments

* test(types): avoid readonly process.env writes in session-cookie tests
2026-03-12 22:14:47 +07:00
Joshua Mo cfe7525200
Add Venice AI integration and model support (#301)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Joshua Mo <joshua-mo-143@users.noreply.github.com>
2026-03-12 22:14:38 +07:00
nyk eaf0bb149e
feat(gateways): add health history logging and timeline (#300) 2026-03-12 18:16:15 +07:00
Nyk 0c209e4c21 test(tasks): replace external repo fixture with neutral local slug 2026-03-12 15:15:55 +07:00
RazorFin 1046f91229
feat(tasks): persist implementation target metadata for deterministic routing (#297)
* Add task implementation target metadata support for heartbeat routing

* test(tasks): verify implementation target metadata persistence and routing precedence

---------

Co-authored-by: clawdbot_nonadmin <clawdbot_nonadmin@clawdbot-admins-MacBook-Pro.local>
2026-03-12 13:18:36 +07:00
HonzysClawdbot a86e939072
fix(session-cookie): migrate to __Host- prefix for secure contexts (#294)
* fix(session-cookie): migrate to __Host- prefix for secure contexts

- Update session-cookie.ts to use __Host-mc-session for HTTPS requests
- Add LEGACY_MC_SESSION_COOKIE_NAME for backward compatibility with HTTP
- Add parseMcSessionCookieHeader() to parse both cookie names
- Add isRequestSecure() helper to detect HTTPS requests
- Update cookie options to enforce Secure, HttpOnly, SameSite=Strict
- Update all call sites (login, logout, google, me, proxy, auth)
- Update e2e tests to support both cookie names
- Update documentation (README.md, SKILL.md, openapi.json)

This addresses the high-priority TODO about migrating to the __Host- prefix
for enhanced security. The __Host- prefix enforces Secure + Path=/ and
prevents subdomain attacks. Legacy mc-session is still supported for HTTP
contexts.

* fix(tests): keep login-flow cookie name aligned with response

- remove unreachable nullish expression in session cookie secure flag

- use returned cookie pair in login-flow spec instead of forcing __Host- prefix

---------

Co-authored-by: Nyk <0xnykcd@googlemail.com>
2026-03-12 12:32:53 +07:00
Jonatan d2bbacbee3
feat(gateway-auth): enhance authentication configuration and credential retrieval (#292)
- Added support for specifying authentication mode ('token' or 'password') in the gateway configuration.
- Updated `getDetectedGatewayToken` function to return the appropriate credential based on the selected mode.
- Improved security scan checks for gateway authentication, ensuring both token and password modes are validated correctly.
2026-03-12 12:29:28 +07:00
Jonatan 83e98d75e1
fix(onboarding): enhance wizard layout and content for improved user experience (#293)
- Adjusted the onboarding wizard's content area to have a maximum height of 70vh for better responsiveness.
- Updated the credentials step to ensure the content area can overflow and scroll, enhancing usability during input.
2026-03-12 12:28:30 +07:00
nyk 55f2351bdc
fix: allow unauthenticated status health probe for container checks (#295)
- allow /api/status?action=health through proxy without session/API key
- short-circuit health action in status route before role gating
- add proxy regression tests for health probe allow + non-health deny

Regression checks:
- pnpm vitest run src/proxy.test.ts src/lib/__tests__/auth.test.ts
- pnpm playwright test tests/auth-guards.spec.ts
- smoke: /api/status?action=health=200, login=200, /api/auth/me=200
2026-03-12 12:22:34 +07:00
nyk a18240381c
fix: resolve open docker and gateway-optional regressions (#291) 2026-03-12 01:53:00 +07:00
nyk 44aaf150c2
security(csp): remove unsafe-inline with nonce-based CSP (#288)
* fix: route coordinator sends to live sessions and parse boxed doctor output

* feat: make coordinator routing user-configurable and deployment-agnostic

* feat: add coordinator target dropdown in settings

* feat(settings): preview live coordinator routing resolution

* security(csp): remove unsafe-inline via per-request nonce policy

* fix(ui): disable new organization CTA; improve skills registry and panel defaults

- disable non-functional New organization button in nav rail
- gate Hermes Memory visibility on actual Hermes CLI binary detection
- optimize agents task stats API by replacing N+1 with grouped query
- make task board render primary data first and hydrate quality-review async
- default skills panel registry source to awesome-openclaw
- add resilient registry search fallbacks for ClawdHub/skills.sh endpoint variants
2026-03-11 23:15:20 +07:00