Commit Graph
875 Commits
Author SHA1 Message Date
viettranx 0f6cebc783 feat: structured compaction summary with identifier preservation
Compaction summaries were too generic ("provide a concise summary"),
causing loss of task progress, decisions, and identifier corruption
after summarization.

Port from OpenClaw TS (compaction.ts):
- Structured MUST PRESERVE sections: active tasks, progress, last
  request, decisions, TODOs, commitments
- Identifier preservation: preserve UUIDs, hashes, URLs, file names
  exactly as written (no shortening/reconstruction)
- Prioritize recent context over older history
- Shared prompt constant used by both mid-loop and background
  compaction paths
2026-03-31 09:32:38 +07:00
viettranx ab5bad11ff feat: cap tool output at source + improve context pruning pipeline
Problem: Agent sessions accumulated 71K+ input tokens (83% history)
because read_file and exec had no output limits. SOUL personality
drowned by massive context.

Changes:
- read_file: add offset/limit params + 50K char output cap with
  pagination hints (model can re-read with offset)
- exec/shell: cap output at 30K chars with smart head+tail truncation
  (preserves errors/summaries at tail)
- pruning: add per-result 30% context guard, tune softTrimRatio
  0.3→0.25 and softTrimMaxChars 4K→3K, add tail-aware soft trim
- mid-loop: allow pruning to re-trigger each iteration (was one-shot)

Design: cap at source, preserve full data in session, prune at
consumption time. read_file offset/limit enables recovery of
truncated content.
2026-03-31 08:35:06 +07:00
viettranx fe163eca30 fix(claude-cli): preserve CLAUDE_CODE_OAUTH_TOKEN in env filter
filterCLIEnv was stripping all CLAUDE* env vars including the OAuth
token needed for CLI subprocess authentication.

Closes #541
2026-03-31 08:19:58 +07:00
Plateau Nguyen dbc93aae8e fix(discord): stop typing after successful delivery (#589) 2026-03-31 08:14:52 +07:00
Kai (Tam Nhu) Tran 343b530480 fix: cap tool call IDs to 40 chars via hash-based uniquification (#590)
Closes #532

- Replace prefix truncation with SHA-256 hash-based shortening for oversized tool call IDs (40-char OpenAI/Azure limit)
- Normalize provider-prefixed model IDs (e.g. openai/o3-mini) before capability checks for temperature and max_completion_tokens
- Add regression tests for ID collision, correlation, and prefixed model routing
2026-03-31 08:10:01 +07:00
Kai (Tam Nhu) Tranandviettranx 3ca3bb2062 feat: add capability-aware reasoning effort controls (#593)
* feat(reasoning): add capability-aware effort resolution

- resolve requested reasoning levels against exact model capabilities

- persist requested effort on agents and expose effective effort in traces

- add backend tests for provider models, agent store, and resolution logic

Refs #591

* feat(ui): gate reasoning controls by model capabilities

- only show supported reasoning levels when provider model metadata is available

- preserve expert reasoning selections during async model loading

- surface effective reasoning details in trace dialogs and localized copy

Refs #591

* docs(api): document capability-aware reasoning controls

- describe exact-match capability lookup and downgrade behavior

- update provider model metadata and trace response documentation

- refresh the generated OpenAPI spec for the new reasoning fields

Refs #591

* feat: add provider-first reasoning controls

* docs: refresh PR 593 UI evidence callouts

* refactor: deduplicate reasoning normalize functions and remove PR evidence

- Export NormalizeReasoningEffort/NormalizeReasoningFallback from providers
  package; store package now delegates instead of duplicating
- Store reasoning fallback constants alias providers canonical definitions
- Export deriveLegacyThinkingLevel from types/provider.ts; remove local
  copies from agent-advanced-dialog and provider-overview
- Remove unused _providerType param from useProviderModels hook
- Fix reasoning debug log to fire for all cases with a reason (not just
  non-off efforts)
- Remove docs/pr-593-evidence/ binary screenshots from repo

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-31 07:56:01 +07:00
viettranx 1dee22aeb7 fix(telegram): add human-like writing instructions for group chats
Port missing group chat style guidance from OpenClaw TS:
- "Write like a human" — prevents robotic/formal GPT responses
- "Avoid Markdown tables" — GPT tends to spam tables in groups
- "Use real line breaks sparingly"

These instructions exist in OpenClaw TS (groups.ts buildGroupIntro)
but were missing in GoClaw's group prompt.
2026-03-31 07:27:57 +07:00
viettranx a47d7f9f4f fix(providers): use developer role for native OpenAI endpoints (GPT-4o+)
GPT-4o+ models prioritize "developer" messages over "system" for
instruction adherence. GoClaw was sending "system" for all providers,
causing GPT models to poorly follow SOUL/system prompts.

Map "system" → "developer" only for native OpenAI endpoints
(api.openai.com). Non-OpenAI backends keep "system" role unchanged.

Ported from OpenClaw TS: model-compat.ts → isOpenAINativeEndpoint()
2026-03-30 23:56:51 +07:00
viettranx 7fd31c34aa fix(telegram): retry 429 rate limit errors and preserve stream messages
429 (Too Many Requests) was not recognized as retryable, causing:
1. editMessage fails with 429 → no retry
2. Stream message deleted as fallback
3. Fresh sendMessage also 429 → message lost entirely

Changes:
- Add 429 to isRetryableNetworkErr (matching OpenClaw TS TELEGRAM_RETRY_RE)
- Honor Telegram retry_after parameter for backoff delay
- Don't delete stream message on retryable errors (keep valid content)
2026-03-30 23:04:26 +07:00
viettranx 33f975edf0 fix: use agent_key instead of UUID for session tool authorization (#573)
Session tools (sessions_list, session_status, sessions_history, sessions_send)
were using resolveAgentIDString(ctx) which returns the agent UUID, but session
keys are built using agent_key. This caused all session tool operations to fail
silently or return "access denied" for every channel.

Replace resolveAgentIDString() with ToolAgentKeyFromCtx() in all four session
tools. Add fail-closed guard for empty agent key.
2026-03-30 22:28:00 +07:00
dale bb5647aaa8 fix sending image via lark (#587) 2026-03-30 22:15:34 +07:00
Kai (Tam Nhu) Tranandviettranx 287946bb9a fix(ui): restore provider-owned Codex pool inherit state (#585)
* fix(ui): restore provider-owned codex pool inherit state

* docs(pr): add before-after UI evidence

* refactor: remove dead hasProviderDefaults param and harden pool rendering

- Remove unused _hasProviderDefaults parameter from buildDraftRouting
  and routingDraftSignature, clean up all call sites and useMemo deps
- Filter deleted providers from selectedPoolProviderNames to prevent
  ghost entries when a saved pool member no longer exists
- Add symmetric backend test for inherit + non-nil provider defaults

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 22:04:23 +07:00
Kai (Tam Nhu) Tran 3fe0633d35 fix: auto-install deps on skill upload before archiving (#559)
Upload handler previously archived skills immediately when deps were
missing. Now calls InstallDeps() first (owner/master tenant only) and
falls back to archive on failure.

Changes:
- Auto-install missing deps during skill upload (same flow as seeder)
- Atomic DB persist: deps state written with CreateSkillManaged in one call
- Per-slug upload mutex prevents concurrent race conditions
- Frontend: warning state (amber triangle) instead of throwing error
- Non-cancellable context for DB write after dep install
- SQLite StoreMissingDeps now works for custom skills (not just system)
- Comprehensive unit + integration tests

Closes #468
2026-03-30 21:58:29 +07:00
Kai (Tam Nhu) Tran 4c60dd021e fix: clarify container-scoped runtime warnings for minimal images (#395)
* fix(ui): clarify container-scoped runtime warnings

* docs(runtime): clarify docker image variant expectations

* test(tools): align media path expectations with workspace policy

* docs(tests): narrow message media path contract wording
2026-03-30 21:44:53 +07:00
Kai (Tam Nhu) Tran 65d0d62acf fix(memory): guard provider embedding dimensions to 1536 schema (#563)
- Reject incompatible explicit provider embedding dimensions on create/update
- Ignore previously saved incompatible dimensions at runtime, fall back to 1536
- Share RequiredMemoryEmbeddingDimensions constant from store package
- Remove dimensions input from provider UI (always 1536 per pgvector schema)
- Add HTTP, runtime, and validation unit tests

Closes #548
Supersedes #410
2026-03-30 21:36:09 +07:00
viettranx 53932cf532 fix(channels): include display name in [From:] annotation for Telegram and WhatsApp
Telegram: senderLabel now includes full name alongside username, e.g.
[From: @nguyennlt (Nguyễn Trần)] instead of just [From: @nguyennlt].
Also uses FirstName + LastName when no username is set.

WhatsApp: add missing [From:] annotation — was the only channel not
annotating sender identity for the LLM.
2026-03-30 21:24:39 +07:00
teexiii b38a078e70 fix(tools): delivered media tracker prevents duplicate file delivery (#579)
Replace naive HasPrefix("MEDIA:") self-send bypass with context-based
DeliveredMedia tracker (PendingTeamDispatch pattern).

write_file(deliver=true) marks paths → message self-send guard checks:
- Already delivered → blocked (no duplicate)
- Not delivered → allowed (fixes runaway retry loop)

Adds 8 test cases for self-send guard + tracker.
2026-03-30 21:13:27 +07:00
teexiii 88a5793030 fix(agents): sync IDENTITY.md Name field on agent rename (#582)
## Summary

- Agent rename now updates Name field in IDENTITY.md (agent-level + per-user copies for open agents) via both HTTP and WS paths
- Fixes lossy identity rebuild: previous logic reconstructed IDENTITY.md from only Name/Emoji/Avatar, silently dropping LLM-written fields (Creature, Purpose, Vibe, etc.)
- Uses targeted field replacement (bootstrap.UpdateIdentityField) preserving original formatting
- Adds ListUserContextFilesByName to AgentContextStore (PG + SQLite)
- Fixes LastIndex bug in UpdateIdentityField where values containing colons (e.g. Avatar URLs) would break field replacement
- Removes ~335 lines of dead config.json fallback code (agentStore is always set)
- Adds 9 unit tests for UpdateIdentityField covering plain/markdown formats, URLs, edge cases
2026-03-30 20:56:49 +07:00
Plateau Nguyenandviettranx 0e2db21345 fix(cron+providers): Run Now stuck fix, type safety, and claude-cli image format (#577, #568) (#580)
* fix(cron): Run Now executes correctly and reset stale running status (#568)

- PG store RunJob now sets next_run_at = NULL before executeOneJob so
  loadClaimedJob (which requires next_run_at IS NULL) succeeds instead
  of silently skipping the forced run
- recomputeStaleJobs on startup resets last_status 'running' → 'interrupted'
  for jobs that were mid-execution when the server crashed
- UI: add typed CronJobPatch interface matching backend store.CronJobPatch
  (deliverChannel/deliverTo/stateless) — replaces Record<string, unknown>
  on updateJob and onUpdate props across cron detail components
- UI: fix enabled/disabled label in overview tab to reflect local state
  instead of stale job prop

* fix(cron): add error handling for ExecContext calls per code review

- RunJob: return error if claiming job (next_run_at = NULL update) fails
  instead of silently proceeding to executeOneJob which would then skip
- recomputeStaleJobs: log warning on failure, log count of reset jobs
- Add log/slog import to cron_exec.go

* fix(providers): claude-cli ChatSync image format mismatch (#577)

When images are present, Chat() now uses stream-json output format to
match the stream-json input format required by Claude CLI >= v2.1.87.

Also adds concurrent execution guard to RunJob() preventing
double-execution when Run Now is clicked rapidly.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 20:37:49 +07:00
therichardngai-code 0ef30ad060 fix(ui): reduce KG graph INP from 808ms to <100ms (#581)
- Defer dialog open via setTimeout(0) on node click — decouples edge
  restyle from dialog mount (808ms → <100ms INP)
- Memoize relations table with React.memo + limit initial render to 50
  rows with "Show all" button (792ms table cell INP → <100ms)
- Added i18n key kg.entity.showAll for en/vi/zh

Based on upstream review fixes (989e4f3).
2026-03-30 20:21:48 +07:00
viettranx 989e4f3123 fix(ui): KG graph review fixes — edge colors, fetch limit, double fitView
- Fix hardcoded dark edge color on deselect — use neutral #64748b
- Reduce graph fetch limit 200→50 to match component render cap
- Fix O(n*m) node lookup on theme change — use Map for O(1)
- Remove double fitView (prop + manual call)
2026-03-30 16:53:14 +07:00
viettranx 88f4fa264a fix(ui): KG graph perf + theme support + entity limit
- Limit graph to 50 entities for smooth DOM-based rendering
- Dual-theme node colors (light: solid bg/dark text, dark: translucent/light)
- Follow user theme via colorMode (no hardcoded dark)
- Theme change updates node colors without re-layout or fitView
- Remove MiniMap, backdrop-filter blur, translateZ GPU layers
- Thicker edges (strokeWidth 2, opacity 0.6) for visibility
- Simplified footer: entity/relation counts + limit note
- memo EntityNode to prevent re-render during pan/zoom
- i18n: add limitNote/limitHint keys (en/vi/zh)
2026-03-30 16:46:25 +07:00
viettranx 1cb7d3cb70 perf(ui): optimize KG graph view for large graphs
- Add KGEdgeData interface replacing `as any` casts for type safety
- Use entityMap (useMemo Map) for O(1) entity lookup instead of O(n) find
- Pre-compute EDGE_STYLE_DEFAULT/FADED constants to reduce GC pressure
- Skip edge object recreation when style unchanged during selection
- Wrap EntityNode in memo() with memoized container style
- Cap force simulation ticks at 200 for graphs with 100+ nodes
2026-03-30 15:54:34 +07:00
therichardngai-code 540fc5e99b feat(ui): enhance knowledge graph with depth visualization and performance fixes (#572)
- Dark canvas with atmospheric radial gradient for depth effect
- Pill-shaped nodes with frosted glass, glow on hub nodes (4+ connections)
- Mass hierarchy in d3-force: org/project anchor center, tasks orbit out
- Degree centrality sizing: more connections = larger node
- Edge labels hidden by default, revealed on node selection with animation
- Deferred force layout via setTimeout(0) — toggle INP: 920ms → ~100ms
- useTransition for node clicks — edge restyle INP: 568ms → 160ms
- Disabled nodesConnectable + pointerEvents:none on handles — zero hover cost
- Added i18n key kg.graphView.selected for en/vi/zh
2026-03-30 15:38:38 +07:00
viettranx 3a6c63904c feat(cron): add stateless mode + promote payload fields to columns
- New `stateless` column: when true, cron runs skip session Reset/Save
  (fresh ephemeral session each run, saves tokens). Default true for new crons.
- Promote deliver, deliver_channel, deliver_to, wake_heartbeat from
  payload JSONB to dedicated columns for queryability and type safety.
- CronPayload now content-only: kind, message, command.
- PG migration 000033: backfills from JSONB, strips promoted keys.
- SQLite migration v2→v3: backfills with json_extract().
- Web UI: stateless toggle in advanced dialog, i18n (en/vi/zh).
- Desktop UI: types + i18n updated.
2026-03-30 15:24:41 +07:00
viettranx 014f74ec15 fix(agent): group session unresponsive during team task execution (#266)
Two fixes:

1. Remove assistant prefill from team task reminders. The injected
   [user]+[assistant]+[user] pattern caused LLMs to treat the canned
   ack as "turn complete", returning NO_REPLY for every user message
   in group sessions with active tasks. Reminders are now merged into
   the user message as prefix tags.

2. Add PeerKind propagation to team notification routing. TaskTicker
   and progress notifications were missing PeerKind on InboundMessage,
   causing them to route to phantom DM sessions instead of the correct
   group session. PeerKind is now carried through event payloads,
   notify queue metadata, and all inbound message publications.
2026-03-30 15:20:01 +07:00
viettranx 24717b0f51 refactor(cron): normalize payload columns into dedicated DB fields (#33)
Extract wake_heartbeat and stateless from JSON payload into first-class
columns on cron_jobs. Adds migration 000033 with backfill from existing
payload data. Updates PG + SQLite stores, RPC handlers, and UI i18n.
2026-03-30 15:19:43 +07:00
viettranx d10236241e fix(agent): add panic recovery to prevent zombie state after agent loop crash (#39)
Root cause: runLoop() had no recover() — panics killed the goroutine while
leaving the session queue's activeRuns entry orphaned. Subsequent messages
to the same session would hang indefinitely (zombie state).

Fix: Two-layer panic recovery:
1. loop.go: runLoop() now returns error on panic instead of crashing goroutine,
   allowing normal cleanup flow (session queue, traces, events)
2. queue.go: executeRun() defense-in-depth recovery ensures activeRuns cleanup
   and scheduleNext() even if agent-level recovery fails
2026-03-30 14:36:25 +07:00
viettranx 4ac611530a fix(store): provider CreateProvider uses UPSERT to handle orphaned duplicates (#295)
CreateProvider now uses ON CONFLICT (tenant_id, name) DO UPDATE instead of
plain INSERT. When a provider with the same name already exists (e.g. orphaned
after agent deletion), it updates the existing record instead of failing with
a unique constraint violation.

Applied to both PG and SQLite implementations.
2026-03-30 14:29:33 +07:00
viettranx bdfc0fadfb fix(config): MCP env: resolution, channel field filter, orphan provider event, workspace fallback (#348, #297, #295, #431)
- manager.go: add resolveEnvVars() to expand env:VARNAME in MCP headers (copy-safe)
- manager_env_test.go: 3 test cases for env resolution
- validate.go: add "name" to channelInstanceAllowedFields
- validate_test.go: test channel instance name field retention
- bus/types.go: add TopicAgentDeleted event + AgentDeletedPayload
- agents_delete.go: emit agent:deleted event with provider name for async cleanup
- gateway.go: log-only subscriber for orphaned provider warning (no auto-delete — FK safety)
- resolver.go: fallback to deps.Workspace for master tenant agents with empty ag.Workspace
  (fixes filesystem escape where filepath.Join("","system") resolved to /system)
2026-03-30 14:12:18 +07:00
viettranx 8eb4ce6d6f fix(store): session Save() UPSERT fallback, memory index-all user_id header (#379, #517)
- sessions_list.go (PG): check rowsAffected after UPDATE, INSERT with ON CONFLICT DO UPDATE
  when session not yet in DB (cron/heartbeat sessions)
- sessions_ops.go (SQLite): same UPSERT pattern with ? placeholders
- memory_handlers.go: fallback to X-GoClaw-User-Id header when body.user_id is empty
2026-03-30 14:12:08 +07:00
viettranx ec060ad7e1 fix(agent): unblock stuck agent on /stop, auto-complete nil-result tasks, graceful shutdown (#527, #504, #39)
- loop.go: replace blocking range with select+ctx.Done() for parallel tool collection;
  document finalization trade-off on early cancel
- loop_cancel_test.go: tests for context cancellation and normal completion paths
- gateway_consumer_post_turn.go: always auto-complete team task in default case,
  fallback message when outcome.Result is nil
- gateway.go: call sched.Stop() with 5s drain before context cancel on shutdown
2026-03-30 14:12:00 +07:00
viettranx e1c52cbda8 fix(providers): prevent crash on cancel, capture thinking signature, nil guard (#287, #188, #566, #335)
- anthropic_stream.go: check ctx.Err() in scanner loop, bounds check toolCallJSON index,
  accumulate signature_delta events into ThinkingSignature
- anthropic_request.go: include signature field in buildRawBlock for thinking blocks
- types.go: add ThinkingSignature field to ChatResponse
- loop_run.go: nil guard on result before FinishTrace access
- gateway.go: defensive ApplyDBSecrets before setupTTS in config reload subscriber
2026-03-30 14:11:52 +07:00
viettranx 011f5f1a3d fix(security): harden env file permissions and block NUL byte injection (#306, #44)
- prepare-env.sh: chmod 600 after .env creation to prevent world-readable secrets
- shell.go: reject commands containing NUL bytes before execution
- credentialed_exec.go: defense-in-depth NUL check in credentialed path
- shell_deny_test.go: add TestExecute_RejectsNULByte with 6 test cases
2026-03-30 14:11:42 +07:00
viettranx 533ca44e99 fix(config): add GOCLAW_ALLOWED_ORIGINS env var for CORS config (#543)
Add env var support for gateway.allowed_origins so container deployments
can set CORS origins reliably even if config file is overwritten by UI
save cycles. Follows same pattern as GOCLAW_OWNER_IDS.
2026-03-30 12:06:51 +07:00
viettranx e27c2cc45e fix: add missing MigrateUserDataOnMerge to test stubs
Interface method added in agent-transfer branch was missing from
seedStubStore and createCaptureStore, breaking CI on main.
2026-03-30 11:49:48 +07:00
Thieu Nguyen 82e86bcce1 fix(cron): resolve default agent from DB and fix update payload (#549) (#562)
- Backend: resolve real default agent UUID from DB when cron job has no
  agent_id, instead of using literal "default" string that fails lookup
- UI: replace free-text agent input with dropdown in create form
- UI: wrap update params in `patch` object matching backend expectation
- UI: send empty string for agentId to explicitly clear agent selection
- UI: add name attribute to Select elements to fix form field warning
2026-03-30 11:45:54 +07:00
viettranx 216b8abac6 fix: Telegram @mention linking + conditional media read prompts
- Convert @mentions to <a href="https://t.me/username"> in HTML formatter
  (Telegram Bot API does NOT auto-link @username in parse_mode: HTML)
- Protect @mentions from italic regex mangling underscored usernames
- Change read_image/read_audio/read_video system prompt from "REQUIRED"
  to conditional — model only reads media when relevant to user's question
- Annotate history media tags so model distinguishes group context images
  from current-turn images
2026-03-30 11:45:33 +07:00
Thieu Nguyenandviettranx e7afa83245 fix: dep_scanner false positive — JS import inside Python f-string (#564)
* fix: skip JS ES module imports in Python string literals during dep scan

dep_scanner falsely matched JS `import mermaid from '...'` inside Python
f-strings as a pip dependency, causing functional skills to be archived.

Add jsFromStringRe check: if a line matching pyImportRe also contains
`from '...'`/`from "..."` (JS ES module pattern), skip it. Valid Python
`import X` never has `from '...'` on the same line.

Closes #544

* fix: add missing stub method + additional edge case tests

- Add MigrateUserDataOnMerge to stubAgentStore in context_file_interceptor_test.go
  (fixes CI build failure — stub was missing new AgentStore interface method)
- Add TestScanFile_MultipleJSImportsInsidePythonString for broader false positive coverage

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 08:37:30 +07:00
viettranx 7f897fe9f5 fix: propagate TenantID in team task dispatch InboundMessage
dispatchTaskToAgent() constructed InboundMessage without TenantID,
causing DB-level MCP servers to be invisible when dispatching team
tasks from the dashboard. Same root cause as #560.
2026-03-30 08:13:36 +07:00
daleandClaude Opus 4.6 7b066b7056 fix: propagate TenantID in channel InboundMessage for tenant-scoped MCP resolution (#561)
All channel handlers (Telegram, Discord, Slack, Feishu) bypassed
BaseChannel.HandleMessage() and manually constructed InboundMessage
without setting TenantID. This caused the consumer to fall back to
MasterTenantID, making DB-level MCP server grants invisible on
non-master tenants while config-file MCP servers worked fine.

Closes #560

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:12:00 +07:00
daleandClaude Opus 4.6 4ac9e01288 fix(secutiry): include tenant ID header in skill upload requests (#558)
The upload() method in http-client.ts was manually building headers
(only Authorization + User-Id), missing X-GoClaw-Tenant-Id. This caused
custom skills to always be created on the Master tenant. Replace with
authHeaders() which includes all required headers.

Closes #557

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:06:13 +07:00
Keithandviettranx 172684a5a7 Add prepare-compose.sh for composable docker-compose (#363)
* Add prepare-compose.sh for composible modules, options and overlays

* feat(prepare-compose): add --quiet and --skip-validation flags

Add loud() function for conditional output. Use --quiet to suppress
normal output, --skip-validation to bypass docker compose config check.

* chore: add mise config to gitignore

* chore: add GOCLAW_DIR env var and update context paths

- Add GOCLAW_DIR to prepare-compose.sh for .env generation
- Fix context paths in docker-compose files to use ${GOCLAW_DIR:-.}
- Restore symlinks in compose.d/ and compose.options/

* fix: broken symlink, safe .env update, export COMPOSE_FILE before validate

- Fix compose.d/00-goclaw.yml symlink: docker-compose.yml → ../docker-compose.yml
- Add compose.d/.gitkeep so directory is tracked
- Export COMPOSE_FILE before running docker compose config validation
- Replace rm+sed .env update pattern with safe temp file approach
- Quote GOCLAW_DIR value in .env to handle paths with spaces

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 08:02:57 +07:00
viettranx 23c227e18d fix(ui): combobox viewport flip, multi-user picker, merge data migration
- fix(ui): combobox dropdown flips above input near viewport bottom using
  bottom-anchored positioning so filtered items shrink upward correctly
- fix(ui): add onSelect callback to Combobox for commit-only events,
  preventing keystroke-adds-badge bug in multi-select mode
- feat(ui): MultiUserPicker shared component for allow/deny user fields
- fix(ui): migrate channel allow_from textarea, team allowed/denied users,
  and config allow_from input to MultiUserPicker with unified search
- fix(ui): remove dead getKnownUsers from use-teams hook
- feat: migrate per-user data on contact merge (context files, overrides,
  profiles, memory) with DO NOTHING conflict strategy — canonical tenant
  user data always wins over newly merged contact data
2026-03-29 23:51:53 +07:00
viettranx 63ed4e9351 fix: filter channel team task events from web UI chat
Admin users were seeing team task notifications from other channels
(Discord, Telegram, Lark) in their web UI chat due to bypassing the
UserID event filter. Added channel check to handleTeamTaskEvent matching
the existing pattern in handleAgentEvent.
2026-03-29 22:37:01 +07:00
viettranx 21b6c454ca feat: merge pipeline, per-user credentials, unified picker, group contacts
- Enable merge UI for linking channel contacts to tenant_users
- Contact → tenant_user resolution with cached lookup (60s TTL)
- MCP per-user credentials via user-keyed connection pool
- Secure CLI per-user credentials with AES-256-GCM encryption
- Unified UserPickerCombobox searching contacts + tenant_users
- Group contact collection with chat title in all channels
- Group permission inheritance via wildcard user_id="*"
- Fix heartbeat using wrong userID in group chats
- Filter internal senders from contact collection
- Add contact_type column (user/group) to channel_contacts
- SQLite schema v2 migration for desktop edition
2026-03-29 22:33:17 +07:00
viettranx 4cb6991fc6 fix: default noisy team notifications to off
Disable progress, failed, commented, and slow_tool notifications
by default — these are too verbose for most teams.
2026-03-29 19:41:35 +07:00
Viet Tran db7a34e4f3 feat: standalone Import & Export page with Teams, Agents, Skills & MCP
Refactors Agent Transfer into standalone /import-export page with 3 scope tabs.

Teams: auto-bundle member agents (config, context files, memory, KG, cron, profiles, workspace). 
Agents: section picker with presets, merge mode support.
Skills & MCP: custom skills + MCP server configs (stripped secrets), conflict detection.

Security: scopeClauseAlias for JOINs, tenant scope on all queries, zip bomb protection, adminMiddleware on import routes.
DRY: shared storeExportToken + readTarGzEntries helpers.
i18n: complete en/vi/zh coverage.
2026-03-29 18:01:08 +07:00
Thieu Nguyen 7b42ab04ab fix(desktop): use 127.0.0.1 instead of localhost and suppress lite startup logs (#546)
- GetGatewayURL/IsGatewayReady: use 127.0.0.1 to avoid WebKit resolving
  localhost to ::1 (IPv6) when gateway only binds IPv4, causing "Load failed"
- Skip CORS warning for lite edition (localhost-only, no production exposure)
- Skip server IP detection for lite edition (no multi-tenant risk, avoids
  leaking user's public IP in logs and unnecessary network calls)
2026-03-29 16:03:09 +07:00
viettranx b59a623649 fix(deps): upgrade major packages across web and desktop UIs
Web UI:
- i18next 25→26, react-i18next 16→17
- lucide-react 0.468→1.7 (no brand icons used)
- tailwind-merge 2→3 (Tailwind CSS 4 compat)
- typescript 5.7→6.0 (remove deprecated baseUrl from tsconfig)

Desktop UI:
- i18next 25→26, react-i18next 16→17
- immer 10→11 (internal perf improvements)
- react-markdown 9→10, react-syntax-highlighter 15→16
- typescript 5.9→6.0
- Fix MarkdownRenderer: wrap ReactMarkdown in div for className (v10 removed prop)

Both: build verified, pnpm audit 0 vulnerabilities
2026-03-29 13:03:39 +07:00