Commit Graph
692 Commits
Author SHA1 Message Date
viettranx 9a24995e56 docs(store): restore inline doc comments on interface methods
Restore 3 godoc comments that were accidentally dropped during
AgentStore/SessionStore interface split: GetDefault hint, CanAccess
return values, and Get vs GetOrCreate distinction.
2026-03-25 09:19:36 +07:00
viettranx 382ec9aa51 refactor(gateway): split teams_tasks method file into queries and mutations
Move task create, assign, delete, bulk delete, and dispatch methods from
teams_tasks.go (858 LOC) to teams_tasks_mutations.go (415 LOC).
Original file reduced to 460 LOC (get, review, comments). No logic change.
2026-03-25 08:40:44 +07:00
viettranx f011b8cd15 refactor(store): split knowledge_graph.go into entity and relation files
Move relation CRUD, batch ingest, prune, stats, and scan helpers from
knowledge_graph.go (731 LOC) to knowledge_graph_relations.go (378 LOC).
Original file reduced to 365 LOC (entity ops + search). No logic change.
2026-03-25 08:36:06 +07:00
viettranx 066ba4dca6 chore: add pkg-helper binary to .gitignore 2026-03-25 08:35:28 +07:00
viettranx 25a123fef9 refactor(store): split AgentStore and SessionStore into focused sub-interfaces
AgentStore (27 methods) → 4 sub-interfaces:
- AgentCRUDStore (10): core CRUD operations
- AgentAccessStore (5): sharing and access control
- AgentContextStore (8): agent-level and per-user context files
- AgentProfileStore (4): user-agent profiles and instances

SessionStore (33 methods) → 3 sub-interfaces:
- SessionCoreStore (16): lifecycle, messages, history
- SessionMetadataStore (13): tokens, timing, calibration
- SessionListingStore (4): search, list, discovery

Both use composed interfaces for backward compatibility (same
pattern as TeamStore split). No implementation changes.
2026-03-25 08:32:24 +07:00
viettranx 7382aceb7e refactor(pkg-helper): extract hardcoded GID to constant and log chown errors
Replace magic number 1000 with goclawGID constant across all chown
calls. Add slog.Warn on chown failures instead of silently ignoring
them, improving debuggability for permission issues in production.
2026-03-25 08:32:00 +07:00
Thieu Nguyen 18824f841d fix(pkg-helper): restore group ownership on apk-packages persist file (#456)
* fix(pkg-helper): restore group ownership on apk-packages persist file

persistRemove() uses write-to-temp-then-rename which creates the new
file as root:root. The goclaw process (uid 1000, gid 1000) can't read
it, causing ListInstalledPackages to return nil for system packages.
After any package uninstall, the UI shows an empty package list.

Fix: chown listFile to root:goclaw (0:1000) after rename in
persistRemove and after initial creation in persistAdd.

* fix(ui): reset uninstall success icon to trash after timeout

After uninstalling a package, the success checkmark icon stayed
permanently instead of reverting to the delete (trash) icon.

Add setTimeout to reset actionStatus from "success" to "idle" after 2s,
matching the existing pattern used for error states.
2026-03-25 08:30:49 +07:00
Thieu Nguyen 424f3a975c refactor(docker): rename network "shared" to "goclaw-net" (#405)
The generic name "shared" conflicts with other projects on the same
host. Use a project-scoped name to avoid collisions.
2026-03-25 08:27:39 +07:00
Luan VuandLuvu182 95ce4200dd fix(ui): session detail missing tool calls, memory dialog toast errors (#458)
1. Session detail: isDisplayable() filtered out assistant messages with
   only tool_calls or thinking (no text content). Live chat renders these
   via MergedToolGroup but session history silently dropped them.

2. Memory document dialog: load error showed "Failed to create document"
   (wrong i18n key toast.failedCreate). Save error used the same wrong key.
   Fixed to use toast.docLoadFailed and toast.docUpdateFailed respectively.
   Added missing docLoadFailed key to en/vi/zh locale files.

3. Memory dialogs: all 5 dialogs missing aria-describedby={undefined} on
   DialogContent, causing Radix UI console warnings about missing
   Description for accessibility.

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-25 08:26:35 +07:00
viettranx 1f72f0d179 fix(docker): harden credential sync and move CLI mount to overlay
- Replace chmod 644 temp file with install(1) -m 600 for atomic copy
  with correct ownership — eliminates world-readable window in /tmp
- Move ${HOME}/.claude volume mount from base docker-compose.yml to
  optional docker-compose.claude-cli.yml overlay — avoids breaking
  deployments where $HOME is unset (CI/CD, systemd, Swarm)
2026-03-25 08:21:11 +07:00
viettranx 2ce975af73 fix(store): restore alias validation guard in WhereClauseAlias
Re-add character-by-character alias validation that was present in the
old tenantClauseNAlias but missing from the new WhereClauseAlias.
Defense-in-depth against SQL injection via table alias parameter.
2026-03-25 08:20:10 +07:00
viettranx a080446db3 refactor(store): remove deprecated tenantClauseN/tenantClauseNAlias
All callers migrated to scopeClause/scopeClauseAlias in previous commit.
Remove the old functions. tenantIDForInsert and requireTenantID retained
(still have callers).
2026-03-25 08:20:10 +07:00
viettranx e81318a663 refactor(store): migrate all tenantClauseN callers to scopeClause
Migrate 72 calls across 16 files from tenantClauseN/tenantClauseNAlias
to scopeClause/scopeClauseAlias. Old functions retained in helpers.go
as definitions only (no callers). All store queries now use the
scope-based helpers, ready for project-level scoping when needed.
2026-03-25 08:20:10 +07:00
viettranx deb821063a refactor(store): add QueryScope abstraction for composable multi-level isolation
Introduce store.QueryScope struct that generates WHERE clauses for
tenant + optional project scoping. Add scopeClause/scopeClauseAlias
wrappers in pg/helpers.go as drop-in replacements for tenantClauseN.

Old tenant-only helpers remain for existing callers (76 occurrences).
Migrate providers.go (4 calls) as proof-of-concept. Future callers
should use scopeClause for project-scope readiness.
2026-03-25 08:20:10 +07:00
viettranx 379da91a68 refactor(agent): extract post-loop finalization to loop_finalize.go
Move sanitization, media dedup, session flush, bootstrap cleanup, and
RunResult construction from runLoop() into dedicated finalizeRun() method.
Reduces loop.go from 1123 to 956 LOC (-167). No behavior change.
2026-03-25 08:20:10 +07:00
viettranx ebef1951bf fix(agent): restore iteration key in slog, event payloads, and LLM prompts
Fix mechanical find-replace that leaked rs.iteration into string literals,
slog keys, and event payload map keys. Restores "iteration" as the
user-facing/frontend-facing key name.
2026-03-25 08:20:10 +07:00
viettranx ae18f24cd9 feat(ui): drag-and-drop file/folder move in Storage and Workspace
Backend:
- PUT /v1/storage/move?from=&to= — admin-only, atomic os.Rename
  with protected dir, path traversal, symlink escape, and overwrite
  prevention checks.
- PUT /v1/teams/{teamId}/workspace/move — same security with team
  membership check and EventWorkspaceFileChanged broadcast.

Frontend:
- Files and folders are draggable in the file tree (HTML5 drag API).
- Folders are drop targets with visual ring highlight on dragover.
- Root-level drop zone for moving items to root directory.
- Guards: can't drop into self, can't drop folder into descendant,
  can't drop into protected dirs (server-side enforced).
- Wired in both Storage page and Team Workspace dialog.
2026-03-25 08:20:10 +07:00
viettranx c1377de943 refactor(agent): extract tool result processing to loop_tools.go
DRY: deduplicate tool result processing between single-tool and parallel-tool
paths. New processToolResult() and checkReadOnlyStreak() methods on *Loop
handle loop detection, event emission, media collection, deliverables, and
spawn tracking. Reduces loop.go from 1324 to 1123 LOC (-201). No behavior change.
2026-03-25 08:20:10 +07:00
viettranx cd7426454e refactor(agent): introduce runState struct to encapsulate loop mutable state
Consolidate ~20 local variables from runLoop() into a single runState
struct. This enables future extraction of loop sub-operations (tool
execution, media processing, streaming) as methods on *runState without
passing individual variables. No behavior change.

Fields moved: loopDetector, totalUsage, iteration, totalToolCalls,
finalContent, finalThinking, asyncToolCalls, bootstrapWriteDetected,
mediaResults, deliverables, pendingMsgs, blockReplies, lastBlockReply,
checkpointFlushedMsgs, midLoopCompacted, teamTaskCreates,
teamTaskSpawns, skillNudge70Sent, skillNudge90Sent, skillPostscriptSent
2026-03-25 08:20:10 +07:00
viettranx 96fbc79cd2 refactor(store): split TeamStore into focused sub-interfaces
Split monolithic TeamStore (61 methods) into 6 focused interfaces:
- TeamCRUDStore: core team + member operations (13 methods)
- TaskStore: task CRUD + lifecycle transitions (22 methods)
- TaskCommentStore: comments, events, attachments (10 methods)
- TaskRecoveryStore: stale detection + recovery (6 methods)
- TaskFollowupStore: follow-up scheduling (7 methods)
- TeamAccessStore: user access grants (5 methods)

TeamStore is now a composed interface embedding all sub-interfaces,
maintaining full backward compatibility. No implementation changes.
2026-03-25 08:20:10 +07:00
viettranx 96bf0ddb68 refactor(agent): extract context injection to loop_context.go
Move agent/tenant/user/workspace context enrichment, input guard, and
message truncation from runLoop() into dedicated injectContext() method.
Reduces loop.go from 1553 to 1346 LOC. No behavior change.
2026-03-25 08:20:10 +07:00
viettranx 81c8414423 refactor(store): fix goroutine safety issues across cron, sessions, skills, and gateway
- Replace 16x bare db.Query/db.Exec with context-aware variants to prevent
  orphan DB operations when parent context is cancelled
- Thread baseCtx through PGCronStore lifecycle (Start/Stop) for all internal
  scheduler, executor, and job cache operations
- Add ctx parameter to StoreMissingDeps and ListSystemSkillDirs, update all callers
- Add sync.WaitGroup tracking to fire-and-forget goroutines in gateway consumer
  handlers (subagent announce, teammate message) with safego.Recover panic protection
- Add safego.Recover to 3 Slack channel goroutines to prevent WaitGroup hang on panic
2026-03-25 08:20:10 +07:00
Luan VuandLuvu182 d63a7d4ced fix(docker): auto-sync host Claude CLI credentials and show Docker-aware login instructions (#398)
When running in Docker, the Claude CLI provider setup showed `claude auth login`
which doesn't work inside a container. This change:

- Mounts host ~/.claude as read-only into the container
- Entrypoint syncs credentials to a writable volume (respects cap_drop: ALL)
- Backend detects Docker via /.dockerenv and returns `in_docker` in auth-status API
- UI shows `docker compose exec goclaw claude auth login` for Docker deployments

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-25 08:19:52 +07:00
viettranx 19eef35653 feat(storage): bump upload limit to 50MB and expand protected dirs
- Increase maxFileSizeBytes from 10MB to 50MB across backend and frontend
- Add media/ and tenants/ to protectedDirs — prevent uploads into
  system-managed directories (only teams/ and custom dirs are writable)
- Update i18n strings (en/vi/zh) to reflect 50MB limit
2026-03-24 23:17:51 +07:00
viettranx 0a57678430 fix(ui): capture active folder for storage upload target
Upload was always going to root because activeFolder derived from
activePath which only tracks file selections (folders expand instead
of selecting). Now capture the folder at Upload button click time
and show the target path in the dialog description.
2026-03-24 22:50:59 +07:00
viettranx 9ee82be219 feat(ui): add file upload to Team Workspace and Storage pages
Allow admins/operators to upload files via the web UI so agents can
read them with read_file during collaboration.

Backend:
- POST /v1/teams/{teamId}/workspace/upload — multipart upload with
  team membership check, tenant isolation, blocked extensions, 10MB
  limit, 100-file quota, symlink escape prevention, and real-time
  EventWorkspaceFileChanged broadcast.
- POST /v1/storage/files — admin-only storage upload with protected
  dir rejection and size cache invalidation.
- Export MaxFileSizeBytes, MaxFilesPerScope, IsBlockedExtension from
  tools package for reuse in HTTP handlers.

Frontend:
- Reusable FileUploadDialog component (drop zone, multi-file,
  per-file status, client-side validation).
- Upload button added to Team Workspace dialog (scope-aware) and
  Storage page (folder-aware).
- i18n strings for en/vi/zh.
2026-03-24 22:48:11 +07:00
viettranx b221ed2fb6 fix(store): add missing WithAgentKey context function
Commit a8815a94 introduced a call to store.WithAgentKey() in
agent/loop.go but never added the function to store/context.go,
breaking the build on main.
2026-03-24 22:47:57 +07:00
viettranx 781ed2a2fd fix(http): inject tenant context in ServeHTTP handlers for multi-tenant isolation
Four HTTP handlers (chat completions, wake, tools invoke, responses) called
resolveAuth() directly instead of using requireAuth middleware, missing
WithTenantID and WithRole context injection. This broke tenant isolation
when backend services used tenant-scoped API keys on these endpoints.

Extract enrichContext() helper from requireAuth to DRY the context setup
logic. Refactor requireAuth and requireAuthBearer to use it. Block wake
endpoint body user_id override when API key has bound owner_id to prevent
impersonation.
2026-03-24 22:15:16 +07:00
viettranx 68406f4a44 fix(slack): prevent app_mention from blocking message handler dedup key
Move the requireMention early-return check before the dedup LoadOrStore
in handleAppMention. Previously, when requireMention=false, an
app_mention event arriving before its corresponding message event would
store the dedup key and return early without processing — causing the
message handler to see the key as already loaded and silently drop the
message (~50% of @mentions lost).
2026-03-24 21:43:25 +07:00
Viet TranandErudition 6bfbfe06c1 fix(slack): enable thread-based session isolation for DMs (AI Panel support) (#449)
Remove the !isDM restriction in the Slack handler, allowing thread_ts to
be propagated for DMs. Add BuildScopedThreadSessionKey for string-based
thread IDs (Slack timestamps) and update the message consumer to detect
thread-scoped local_key values and override the session key.

This enables Slack's AI Panel "New Chat" to correctly start fresh GoClaw
sessions with clean history.


Closes #435

Co-authored-by: Erudition <erudition@users.noreply.github.com>
2026-03-24 21:27:41 +07:00
Thieu Nguyen 05c8b1f1dc [In Progress] fix(ui): show toast error when package install/uninstall fails (#440)
* fix(ui): show toast error when package install/uninstall fails

HttpClient throws ApiError on HTTP 500 responses, but installPackage
and uninstallPackage hooks did not catch the exception. This caused
the error to propagate past the toast logic, so users saw no feedback
when a system package failed to install.

Wrap http.post calls in try/catch to always show toast with the server
error message. Update PackageSection handlers to check res.ok instead
of relying on try/catch for flow control.

* fix(ui): truncate verbose package error in toast notification

Extract last meaningful error line (e.g. "ERROR: ...") from package
manager output instead of dumping the full multi-line response into
the toast, which caused text overflow.

* fix(ui): wrap long text in toast instead of truncating

Add break-words and min-w-0 to toast content so long error messages
(URLs, package manager output) wrap properly within the toast element.
Remove shortError helper — show full error with proper wrapping.

* fix(ui): constrain toast container width to prevent overflow

Move max-w-sm from toast item to the fixed container so long text
(URLs, multi-line errors) is properly bounded. Add overflow-hidden
on toast items as a safety net.

* fix(pkg-helper): re-add packages cascade-removed by apk del

apk del removes orphaned dependencies, which may include other
user-installed packages if they were pulled in as transitive deps.
After uninstalling, check which persisted packages are still present
and re-install any that were accidentally removed.

* revert: remove cascade re-add logic from pkg-helper

apk del does not cascade-remove other world packages (verified via
Docker test). The re-add logic was based on incorrect assumption.
Root cause of the all-packages-deleted issue needs further investigation.
2026-03-24 21:15:22 +07:00
therichardngai-code 00db30c2d1 fix(agent): set TenantID on streaming events in runLoop emitRun (#445)
The emitRun wrapper in runLoop (loop.go) is missing TenantID, causing
all streaming events (chunk, thinking, tool.call) to be emitted with
TenantID=Nil. The event filter (event_filter.go:43-44) blocks unscoped
events for non-admin clients, so tenant-bound API key users receive no
streaming — only run.started and run.completed (emitted from Run() in
loop_run.go which already sets TenantID).

Fix: add event.TenantID = l.tenantID, matching the pattern in
loop_run.go's emitRun wrapper.
2026-03-24 21:14:48 +07:00
Duc Nguyenandviettranx af3fe2fe08 fix: add panic recovery to tool, cron, and summarization goroutines (#420)
* fix: add panic recovery to tool, cron, and summarization goroutines

A panicking tool, cron job, or auto-summarization goroutine crashes
the entire server process — disconnecting all clients and aborting
all running agents. Add defer/recover at three levels:

- safeExecute() in tools/registry.go: catches panics from any tool's
  Execute method and returns an error result to the LLM
- Agent loop goroutine (loop.go): defense-in-depth for non-tool code
  in the parallel tool execution goroutine
- Cron execution goroutine (service_execution.go): prevents a single
  panicking cron job from taking down the server
- Summarization goroutine (loop_history.go): prevents background
  auto-summarization panics from crashing the process

All recovery points log the panic value and stack trace at ERROR level
for debugging. Tool execution panics return actionable error messages
to the LLM so the agent can recover gracefully.

* refactor: extract panic recovery into safego.Recover helper

DRY the duplicated recover+stack+log boilerplate across 4 goroutine
sites into a shared safego.Recover(onPanic, attrs...) function.
Stack buffer bumped from 4096 to 8192 bytes.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-24 21:09:16 +07:00
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