Commit Graph
659 Commits
Author SHA1 Message Date
Duc Nguyenandviettranx ebc82d3265 fix: clear cron session in DB when not cached (cold-cache after restart) (#424)
* fix: clear cron session in DB when not cached (cold-cache after restart)

Fixes #365

PGSessionStore.Reset() only cleared the in-memory cache. After a server
restart the cache is empty, so Reset was a no-op — the next GetOrCreate
loaded the full accumulated history from DB, causing LLM tool loops from
contradictory context.

Add a DB fallback: when the session isn't in cache, issue a direct
UPDATE to clear messages and summary in PostgreSQL. This ensures cron
sessions always start clean regardless of server restarts.

The #294 fix (Reset+Save before each cron run) already had the right
intent but only worked within the same server lifetime.

* fix: move DB call outside mutex and log errors in Reset cold-cache path

ExecContext was running under s.mu.Lock(), blocking all session cache
operations during DB round-trip. Release the lock before the DB call.
Also log ExecContext errors instead of silently discarding them —
silent failure defeats the purpose of the cold-cache fix.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-24 20:47:44 +07:00
viettranx 4276c043c6 fix(ui): scope API key create dialog to current tenant only
Owner sees only "System" + current tenant in dropdown (not all tenants).
Default selection is current tenant instead of system.
2026-03-24 20:45:54 +07:00
viettranx 7aa47d1baf refactor(security): remove cross-tenant bypass, enforce strict tenant isolation
- Add RoleOwner ("owner") to permissions hierarchy (above admin)
- Replace all IsCrossTenant/client.IsCrossTenant() permission guards with
  IsOwnerRole/client.IsOwner() role-based checks (20+ locations)
- Remove cross-tenant bypass from tenantClauseN SQL helper — always adds
  AND tenant_id = $N (fail-closed)
- Add explicit unscoped store methods for startup: ListAllProviders,
  ListAllInstances, ListAllEnabled, GetByIDUnscoped, GetTeamUnscoped
- Remove CrossTenant from auth layer: owner users get role "owner" with
  concrete tenant ID (MasterTenantID fallback), no bypass flag
- Remove crossTenant field from WS Client; connect response sends
  is_owner instead of cross_tenant
- Simplify event filter from 3-mode to 2-mode (tenant-scoped + owner sees system events)
- Fix channel instance loader to use inst.TenantID for agent lookup
- Fix agent embedding goroutine to capture tenant from caller context
- Fix provider cache invalidation to use event.TenantID
- Separate skills store: ListAllSystemSkills (system only) vs
  ListAllSkills (system + tenant-scoped), StoreMissingDeps restricted
  to system skills only
- Frontend: isCrossTenant → isOwner, add "owner" to UserRole type,
  RequireAdmin uses hasMinRole for owner > admin hierarchy
2026-03-24 20:40:59 +07:00
Minh NguyenandMinh Nguyen 7143dcf32c fix(ui): isolate contact search cache key (#434)
Co-authored-by: Minh Nguyen <gbut.277@gmail.com>
2026-03-24 16:05:03 +07:00
viettranx 651072a9ea feat(config): add system_configs DB table with per-tenant isolation and System Settings modal
- Add system_configs table (migration 029) with per-tenant key-value config
- Add SystemConfigStore interface with strict tenant isolation (no cross-tenant fallback)
- Add ApplySystemConfigs overlay: DB values → in-memory cfg at startup + after save
- Add System Settings modal (navbar gear icon) with 3 sections:
  - Embedding: verified 1536d models (OpenAI, OpenRouter, Mistral), custom verify endpoint
  - UX Behavior: tool_status, block_reply, intent_classify toggles
  - Pending Compaction: provider/model + threshold/keepRecent/maxTokens
- Fix block_reply label inversion: ON = delivers intermediate text (not suppresses)
- Fix embedding status endpoint to read from system_configs DB (not provider JSONB)
- Fix config page save to only sync current tenant (not all tenants)
- Fix bus event payload to use fresh context (prevent canceled request context)
- Remove config.json fallback for embedding provider/model resolution
- Add "More Config" link in modal footer to full config page
- Add i18n for system-settings namespace (en/vi/zh)
2026-03-24 16:01:02 +07:00
viettranx 0209f6f970 Revert "fix(http): propagate cross-tenant context in HTTP auth middleware (#427)"
This reverts commit 39b7c689f2.
2026-03-24 11:40:54 +07:00
Duc Nguyen 39b7c689f2 fix(http): propagate cross-tenant context in HTTP auth middleware (#427)
The requireAuth and requireAuthBearer middlewares correctly detect
cross-tenant admin status (gateway token + owner user ID) but never
call store.WithCrossTenant(ctx). This causes all HTTP tenant management
endpoints (GET/POST /v1/tenants, etc.) to return 403 "insufficient role"
because handlers check store.IsCrossTenant(ctx) which was always false.

The WebSocket path works correctly because the gateway Client object
tracks cross-tenant status independently via client.IsCrossTenant().

Fix: Add store.WithCrossTenant(ctx) in both auth functions when
auth.CrossTenant is true, matching the design of the WS path.

Affected endpoints:
- GET/POST /v1/tenants (list, create)
- GET/PATCH /v1/tenants/{id} (get, update)
- GET/POST/DELETE /v1/tenants/{id}/users (membership)
- Any future endpoint checking store.IsCrossTenant(ctx)
2026-03-24 11:28:53 +07:00
Duc Nguyenandviettranx eab3766c5f fix: check errors in cron store Scan and Unmarshal to prevent data corruption (#422)
* fix: check errors in cron store Scan and Unmarshal to prevent data corruption

Three unchecked errors in the cron store could silently corrupt data:

1. cron_update.go:44 — QueryRowContext().Scan() error ignored when
   fetching current schedule during partial updates. If DB fails,
   all schedule fields default to zero values, corrupting schedule_kind
   to empty string and bypassing all validation.

2. cron_update.go:167 — json.Unmarshal error ignored when parsing
   existing payload for merge. Corrupted JSON leaves payload zero-valued,
   wiping all existing fields (Message, Deliver, Channel, To) when
   only one field was being updated.

3. cron_scan.go:63 — json.Unmarshal error ignored when scanning cron
   job rows. Malformed payload JSON silently returns zero-valued payload,
   masking data corruption.

All three now return descriptive errors instead of proceeding with
corrupted data. NULL payload (valid case) is handled separately.

* fix: add NULL payload guard and check Marshal error in cron update

- Add len(payloadJSON) > 0 guard before Unmarshal in UpdateJob payload
  merge path, consistent with the same guard in scanCronRow. Without
  this, NULL payload (valid for new jobs) would return a false error
  instead of proceeding with the merge.

- Check json.Marshal error instead of discarding it, consistent with
  the error-checking theme of the parent commit.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-24 10:43:08 +07:00
badgerbees 7fa2d201fb fix(agent): strip internal routing tags from outbound delivery (#416)
- Introduced StripMessageDirectives in the agent loop to remove internal
  [[name:value]] routing tags from user-facing content while preserving
  them in session store for model context
- Narrowed regex from wildcard `(?s)\[\[.*?\]\]` to structured
  `\[\[\w+(?::[^\]\n]+)?\]\]` to avoid false positives on legitimate content
- Preserved [[tts...]] tags for TTS AutoTagged pipeline compatibility
- Added 15 unit tests covering strip, preserve, and edge cases
- Fixed step numbering in agent loop (steps 5-9)
2026-03-24 10:24:10 +07:00
Luan VuandLuvu182 0881d7fc4e docs: use make up in Docker quick start, add optional service flags (#404)
- Update README Docker section to use `make up` instead of raw
  docker compose commands. `make up` handles network creation,
  version embedding from git tags, and database migrations.

- Add WITH_* flags to Makefile for optional compose services:
  WITH_BROWSER, WITH_OTEL, WITH_SANDBOX, WITH_TAILSCALE, WITH_REDIS.
  Uses WITH_ prefix to avoid conflicts with common env vars (e.g.
  BROWSER is set by many desktop environments).

- Document common make commands (up/down/logs/reset) and optional
  service flags with descriptions in a table format.

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-24 10:00:13 +07:00
viettranx c43a8f125b fix(security): harden MCP bridge auth and add startup security warnings (#306)
MCP bridge now returns 403 when no gateway token is configured instead
of serving tools without authentication. Startup warnings added for
default Postgres password and open CORS configuration.
2026-03-24 09:59:07 +07:00
viettranx aadc4d6498 feat(teams): smart post-turn task decision, stale detection, and notification guardrails
- Add TaskActionFlags context-based tracking for member tool calls
  (Completed, Reviewed, Escalated, Progressed, Commented, Claimed)
- Replace aggressive auto-complete with flag-based switch/case:
  tool-completed → skip, reviewed → skip + renew lock,
  progress-only → renew lock (don't auto-complete),
  no flags → auto-complete (backward compat)
- Fix executeReject to use RejectTask (strict in_review guard)
  with auto re-dispatch that preserves dependent task blocking
- Add ticker Phase 4: mark in_review tasks stale after 4 hours
- Add ticker Phase 5: fix orphaned blocked tasks (all blockers terminal)
- Keep owner_agent_id during lock recovery for auto re-dispatch
- Add RunKind="notification" to team notify inbound messages
  with mutation blocking in TeamTasksTool (read-only enforced)
- Increase MessageBus buffer 500 → 1000
- Add ResetTaskStatus support for cancelled and in_review sources
2026-03-24 08:56:10 +07:00
viettranxandBadgerbees 6a2949de4a fix(telegram): clear draft after materializing DM stream
When using draft_transport in Telegram DMs, the preview draft sometimes
stays in the input area after the real message is delivered, showing a
brief duplicate reply.

Clear the stale draft by sending an empty sendMessageDraft as soon as
the final message is sent in Send(). The cleanup is asynchronous and
best-effort so it won't block message delivery.

Co-authored-by: Badgerbees <rapabelias@gmail.com>
2026-03-24 07:51:13 +07:00
viettranx 0bce64032a refactor(ui): move About button back to user menu dropdown 2026-03-24 00:09:42 +07:00
viettranx fe26f2d3e0 fix(ui): correct license to CC BY-NC 4.0 and move About to header
- Fix hardcoded MIT license → CC BY-NC 4.0 with link to CC website
- Move About button from user menu dropdown to topbar header
- Shorten menu label to "About" / "Giới thiệu" / "关于"
2026-03-24 00:06:54 +07:00
huyluseoandhuyluseo a550a13766 feat(ui): add About GoClaw dialog to user menu (#387)
* feat(ui): add About GoClaw dialog to user menu

- Add AboutDialog showing version, source code, license, docs, and bug report links
- Add "About GoClaw" item to UserMenu (with Info icon)
- Add i18n for en, vi, zh

* fix(docker): pass VERSION build arg to Dockerfile

Without this, Docker builds always produce `dev` as the version string.
Users can set GOCLAW_VERSION in .env or environment to embed the correct
version (e.g. from `git describe --tags --always`).

* feat(ui): show update status in About dialog

- Clean version display (strip git commit hash suffix)
- Show "Up to date" badge when on latest version
- Show update banner with link to release notes when new version available
- Fetch health data on dialog open to get latest update info
- Add i18n keys for update status (en, vi, zh)

* refactor(ui): clean version display across all UI locations

Extract cleanVersion() to shared utility. Apply to:
- About dialog (already had it inline)
- Sidebar connection status footer
- Overview page header

"v2.5.1-3-g4fd653c1" now displays as "v2.5.1" everywhere.

* feat(ui): show version in System Health card instead of header

- Add version cell with Tag icon to SystemHealthCard grid
- Green check when up to date, red when update available
- Revert cleanVersion from overview header (keep upstream behavior)
- Add i18n for systemHealth.version (en, vi, zh)

* fix(ui): move version to System Health card header to preserve grid layout

Version now shows in the card header row (right side) instead of as a
grid cell, keeping the original 6-cell (2x3) layout intact.

---------

Co-authored-by: huyluseo <thanhhuylu@example.com>
2026-03-23 23:53:06 +07:00
viettranx a7c34a6087 fix: address 4 bugs from issue #294 — context propagation, cron reliability, crash safety
1. Stale user_context_files after agent file update (#294.1)
   - Added PropagateContextFile() to AgentStore — single CTE query copies
     agent-level file to all existing user instances
   - Added `propagate` param to agents.files.set WS handler
   - Response includes `propagated` count

2. Cron session reuse — tool errors block future runs (#294.2)
   - Reset + Save cron session before each run
   - Each run starts clean, persisted to DB to survive restarts

3. Write-behind cache risk — crash loses messages (#294.3)
   - Added periodic checkpoint flush every 5 tool iterations
   - Messages persisted to session incrementally during long runs
   - Token calibration tracks checkpointed messages correctly

4. Silent cron delivery failures (#294.4)
   - Added slog.Warn when deliver=true but channel/chatID missing

Closes #294
2026-03-23 23:41:27 +07:00
viettranx e2dbd308f5 fix(ui): sync topbar nav item font sizes to text-sm
All topbar items (Documents, Language, Timezone, User menu) now use
text-sm consistently. Previously, non-select items used text-xs (12px)
while Select triggers inherited md:text-sm (14px) from the base
SelectTrigger component, causing a visible mismatch.
2026-03-23 23:41:10 +07:00
Nguyễn Hoàng Thức 0755df4998 fix(test): align TestResolveMediaPath with effectiveRestrict hardening (#381)
Two issues fixed:

1. effectiveRestrict() now always returns true (multi-tenant security),
   so the "unrestricted" test case expected wrong results — paths outside
   workspace are now blocked regardless of the restrict parameter.

2. Tests used bare Unix paths (/etc/passwd) which are not absolute on
   Windows (no drive letter), causing them to resolve inside the workspace
   and pass incorrectly. Added outsidePath() helper that prepends the
   volume name for cross-platform absolute paths.
2026-03-23 23:26:01 +07:00
7db55c67f6 fix(vision): fix Lark inline image parsing and MCP bridge read_image (#396)
* fix(vision): fix Lark inline image parsing and MCP bridge read_image

Two fixes for image reading through Lark channel with claude-cli provider:

1. Lark post messages use flat format {"content":[[...]]} but resolvePostElements
   only handled language-wrapped format {"zh_cn":{"content":[...]}}. Now checks
   flat format first, and skips non-map values in fallback iteration.

2. read_image tool failed via MCP bridge because bridge creates fresh HTTP context
   losing WithMediaImages. Fix: enrich <media:image> tags with path attribute
   (like documents), pass workspace through X-Workspace bridge header with HMAC,
   so read_image can load images from disk via path parameter.

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

* fix(security): add HMAC backward compat and guard workspace injection

- VerifyBridgeContext falls back to old signature format (without workspace)
  for sessions with pre-existing MCP configs, preventing 403 on server restart
- Workspace context injection now requires agent context (agentID/userID)
  to prevent unauthenticated path injection bypassing HMAC

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-23 23:11:33 +07:00
viettranx 462727ec8e fix(ui): reduce combobox focus ring to match Input component
ring-[3px] was clipping against dialog overflow boundaries.
Use ring-1 to match the standard Input component styling.
2026-03-23 22:57:49 +07:00
viettranx 83c79d1b3c feat(mcp): allow admin to set user credentials on behalf of any user
Add ?user_id query param to MCP credential endpoints so system admins
and tenant admin/owner can manage credentials for other users.

Backend:
- Add resolveTargetUserID() with permission checks (system admin,
  tenant admin/owner) and cross-tenant defense-in-depth
- Add TenantStore dependency to MCPUserCredentialsHandler

Frontend:
- Add searchable Combobox user selector for admin users in the
  credentials dialog (visible only when canManageUsers)
- Update credential API calls to pass optional userId param
- Add i18n keys for admin mode (en/vi/zh)
2026-03-23 22:57:39 +07:00
viettranx e1cb5c411b refactor(http): move gateway token to package-level auth state
Replace per-handler `token string` field with package-level
`pkgGatewayToken` via `InitGatewayToken()`, matching the existing
pattern for `pkgAPIKeyCache`, `pkgOwnerIDs`, etc.

- Remove `token` from ~30 HTTP handler structs and constructors
- Simplify `requireAuth(minRole, next)` signature (was 3 params)
- Simplify `resolveAuth(r)` signature (was 2 params)
- Rename `resolveAuthBearer` → `resolveAuthWithBearer` (clearer)
- Add `store.WithRole()`/`RoleFromContext()` to propagate caller
  role through context
- Inject role into context in `requireAuth` and `requireAuthBearer`
2026-03-23 22:57:26 +07:00
viettranx 5b749faa35 fix(teams): prevent leader self-assignment causing dual-session loop
Block team lead from being assigned as task owner across all dispatch
paths. When a leader assigns a task to itself, it gets dispatched to a
team session while still running on the main session — causing race
conditions, duplicate work, and potential infinite announce loops.

Guards added:
- executeCreate: reject assigneeID == team.LeadAgentID
- dispatchTaskToAgent: safety net auto-fail (retry/ticker edge cases)
- DispatchUnblockedTasks: auto-fail leader-owned pending tasks
- ProcessPendingTasks: skip before AssignTask
- executeRetry: explicit error before dispatch
- TeamsMethods.dispatchTaskToAgent: guard for WS/dashboard path

Also removed redundant GetTeamForAgent DB call in dispatchTaskToAgent
by passing *store.TeamData directly from callers.
2026-03-23 22:57:06 +07:00
viettranx 6e80a1af61 fix(skills): unblock agent read_file on skill paths and fix web UI file browser
- Add builtinSkillsDir + tenant-scoped dirs to read_file AllowPaths
- Use DB file_path in HTTP skill file handlers instead of hardcoded baseDir
- Add bundled dir fallback (system skills only) when managed copy is missing
- Tenant-scope publish_skill tool destination directory
- Extract walkSkillFiles/readSkillFile/skillSlugDir helpers (DRY)
- Return is_system from GetSkillFilePath for security-guarded fallback
2026-03-23 22:06:39 +07:00
viettranx b9d875472f refactor(ui): replace API Docs sidebar item with Documents header link and remove notification bell
- Remove "API Docs" from sidebar menu
- Add external "Documents" link (docs.goclaw.sh) to topbar header
- Remove unused notification bell icon from topbar
2026-03-23 18:05:27 +07:00
viettranx dc7f91b9f6 refactor(ui): simplify setup-skip storage logic
Remove side-effect migration code, unnecessary encodeURIComponent,
and implicit localStorage fallbacks from setup-skip utilities.
2026-03-23 17:50:01 +07:00
Minh NguyenandMinh Nguyen eaa0aecccf fix(ui): scope setup skip state by tenant (#372)
Co-authored-by: Minh Nguyen <gbut.277@gmail.com>
2026-03-23 17:49:17 +07:00
4868f6c4d8 feat(gateway): add version update checker (#374)
* feat(gateway): add version update checker

Check GitHub releases periodically (1h) and surface update availability
in the health endpoint + dashboard header. Version is auto-detected from
git tags via Makefile, falling back to VERSION file or build arg.

Backend: new UpdateChecker goroutine, health response includes
latestVersion/updateAvailable/updateUrl fields.

Frontend: version badge in overview header with clickable "available"
link when a newer release exists.

* fix(gateway): fix update checker compile errors and harden GitHub API call

- Export UpdateChecker/NewUpdateChecker to match server.go references
- Move StartUpdateChecker(ctx) after ctx declaration in gateway startup
- Add User-Agent header for GitHub API compliance
- Limit response body to 1MB via io.LimitReader
- Use strconv.Atoi instead of manual int parsing in parseSemver

---------

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-23 17:37:19 +07:00
viettranx 6b29ea056c fix(channels): propagate tenant_id to pending history for compaction/sweep
Channel factories create PendingHistory before InstanceLoader calls
SetTenantID on the channel, so tenantID was always uuid.Nil causing
"tenant_id required" errors on compaction sweep and auto-compact.

Fix: add SetTenantID to PendingHistory and propagate it from
InstanceLoader after channel creation. Also fix HTTP compact endpoint
using context.Background() instead of preserving request tenant context.
2026-03-23 17:28:49 +07:00
viettranx 59a52f1e2f fix(ui): replace bare crypto.randomUUID with uniqueId fallback and show WS disconnect error
- use-chat-sessions, skill-upload-dialog: replace crypto.randomUUID()
  with uniqueId() which has a UUID v4 fallback for non-secure contexts
  (HTTP without localhost) where crypto.randomUUID is unavailable
- use-chat-send: show localized error message when WebSocket is not
  connected instead of silently dropping the send
- Add error.notConnected i18n key to en/vi/zh chat locale files

Closes #352
2026-03-23 16:12:07 +07:00
viettranx 072d98a856 fix(channels): extract and download images from Lark post messages
Post messages with embedded img tags were only producing [image]
placeholder text — the actual image_key was discarded and never
downloaded. Now extractPostImageKeys() collects image keys from
post JSON, and resolvePostImages() downloads them via the existing
Lark resource API. Also handles reply-to-post with images.

Refactored: shared resolvePostElements() helper for language variant
lookup, mediaMaxBytes() helper, and dedup via seen map.
2026-03-23 15:56:11 +07:00
viettranx 9aaec59527 fix(channels): add periodic sweep for pending message compaction
Auto-compaction stopped working after server restarts because provider
resolution failure was silent and there was no retry mechanism. Add a
10-minute periodic sweep in the flusher loop that checks DB for groups
exceeding the compaction threshold, and warn when compaction provider
cannot be resolved at startup.
2026-03-23 15:45:35 +07:00
viettranx ed840dd6d7 fix(ui): use UTC timestamps and timezone-aware message display
Normalize message timestamps to UTC in backend, extract shared
messageToTimestamp helper (DRY), and render chat times using the
user's selected timezone from the topbar setting.
2026-03-23 15:21:32 +07:00
haidang1810 19d7d86030 fix(ui): use server timestamps for chat messages (#332) (#367) 2026-03-23 15:17:31 +07:00
viettranx f9b8ae1b76 fix(ui): fix cron page crash + redesign detail with markdown
- Add key props to cron routes (matching Agents/Sessions pattern)
- Fix React Rules of Hooks violation in CronPage (hooks after early return)
- Redesign overview tab: markdown preview/edit toggle for message,
  info grid with icons, agent select dropdown instead of raw UUID input
- Redesign run history: expandable entries with markdown for summary/error
- Show agent display name instead of UUID in list row, header, and overview
- Add i18n keys (edit, preview, noMessage) for en/vi/zh
2026-03-23 15:07:11 +07:00
viettranx e156e47343 fix(skills): add missing tenant_id to UpsertSystemSkill INSERT
After migration 000027 dropped the tenant_id default on skills table,
new system skill inserts failed with NOT NULL constraint violation.
2026-03-23 15:03:27 +07:00
viettranx 461397d710 docs: add multi-tenant architecture image to README 2026-03-23 14:37:42 +07:00
viettranx 4a03670bc8 fix: address 7 bugs from codebase review
1. providers/anthropic_stream.go — check scanner.Err() after SSE loop;
   truncated responses returned silently on network errors

2. config/config_load.go — trim whitespace in GOCLAW_OWNER_IDS;
   trailing spaces caused owner exact-match failures

3. cron/service.go — handle saveUnsafe() errors at 5 call sites;
   disk I/O failures lost cron state silently

4. tasks/task_ticker.go — separate timeouts for followups (15s) and
   recovery (30s); shared context risked followups starving recovery

5. hooks/use-ws-event.ts — useRef pattern for handler to prevent
   subscribe/unsubscribe churn with inline functions

6. markdown-renderer.tsx — AbortController for file fetch with abort
   on new fetch and on unmount

7. mcp-form-dialog.tsx — auto-split Command field when user pastes
   full command; fix splitShellTokens to preserve commas inside quotes
2026-03-23 14:16:40 +07:00
viettranx cb37383ccd feat(ui): show server version in sidebar connection status
Replace hardcoded "0.2.0" in WS connect response with the actual
build-injected version. Wire server version through WS client → auth
store → sidebar footer so it displays next to connection status.
2026-03-23 14:00:00 +07:00
viettranx 2d9d8adb0c docs: translate model steering system doc to English 2026-03-23 14:00:00 +07:00
viettranx ae6615d962 feat(teams): blocker escalation, audit events, review workflow + docs
- Add comment_type column (note/blocker) with migration 000028
- Blocker comments auto-fail task, cancel member session via
  EventTeamTaskFailed broadcast, and escalate to leader via
  InboundMessage (system:escalation bypasses debounce)
- Enrich audit events: fix tenant scope bug (context.Background →
  WithTenantID), add 4 missing types (commented/progress/updated/stale),
  populate data field (reason, comment_text, progress_percent)
- Add blocker escalation config toggle in team settings UI
- Add audit logs modal with paginated team events (Clock icon)
- Update features modal: all features now available (no coming soon)
- Update code comments: reviewer role not yet active, all flows via leader
- Update docs: remove v1/v2 versioning, add blocker escalation and
  review workflow sections, document enriched audit events
2026-03-23 13:51:28 +07:00
viettranx 8d3eb5bb6f feat(teams): task hints for weak models + force v2
- Add lead hint in search/list results with member+model info and task
  creation guidelines (description quality, complexity, model matching)
- Add member instructions in dispatch message (progress, comment, complete)
- Include member comments and attachments in announce content to leader
- Cap announce content at 50k runes to prevent context blowup
- Remove duplicate comment block in announce path
- Force all teams to v2: remove IsTeamV2 gate, v2Actions map,
  isConsumerTeamV2, and v1 TEAM.md branch
- Replace version comparison modal with features showcase modal
- Remove version selector from team settings UI
2026-03-23 12:14:29 +07:00
viettranx 57f249a89d fix(gateway): prevent panic on send to closed WebSocket client channel
Agent run goroutines can outlive the WebSocket client (e.g. after
reconnect). When the goroutine finishes and calls SendResponse/SendEvent,
the closed send channel causes a panic that crashes the server.

Add defer/recover to both methods to gracefully drop messages for
disconnected clients instead of panicking.
2026-03-23 12:11:47 +07:00
viettranx 2739984aed fix(telegram): resolve getUpdates long-poll timeout race (#361)
HTTP client timeout (30s) equaled getUpdates API timeout (30s), causing
context deadline exceeded errors (~210/hr) when Telegram held the
long-poll for the full duration. Increase HTTP client to 60s, reduce
getUpdates to 25s for 35s headroom.

Closes #361
2026-03-23 12:04:49 +07:00
viettranx 94f6bf2445 fix(security): close shell deny gaps for halt, su, doas, pkexec, runuser
Add missing deny patterns discovered during security audit:
- destructive_ops: halt, init/telinit 0|6, systemctl suspend/hibernate
- privilege_escalation: broaden su to block all forms (bare su, su root),
  add doas, pkexec (CVE-2021-4034), runuser
2026-03-23 10:59:26 +07:00
viettranx 0973b842a2 fix(ui): resolve nested button error and stale agentId in chat
- Provider list: change outer <button> to <div role="button"> to fix
  invalid nested <button> HTML (delete button inside row button)
- Chat page: derive agentId via useMemo from URL session key instead of
  useState initializer that only runs once (stale on session switch)
- Agent change no longer creates ghost sessions — navigates to /chat
  and lets handleSend create session on first message
- Clear messages when navigating away from session (empty key only);
  session-to-session switch still replaces atomically via loadHistory
- Split ROUTES.CHAT into CHAT (nav) + CHAT_PATTERN (route definition)

Closes #349
2026-03-23 10:44:03 +07:00
Kai (Tam Nhu) Tran 2ac5eb6c4b feat(login): add theme toggle to login page (#354) 2026-03-23 10:18:21 +07:00
Kai (Tam Nhu) Tran 40b01d989d fix(summoning): prevent identity markdown from corrupting display names (#356) 2026-03-23 10:17:47 +07:00
viettranx a9a40a3046 fix(zalo): allow QR session restart with race-safe cancel (#346)
Cancel previous QR session when user retries instead of blocking with
"QR session already active". Uses sync.Map.Swap for atomic replacement
and CompareAndDelete so old goroutines don't clobber new sessions.
2026-03-23 08:16:09 +07:00