Create a unified error module (src/errors/index.ts) that provides:
- ClawdbotError: Base error class with code and metadata support
- Common utilities: getErrorMessage, getErrorCode, getErrorStatus,
formatErrorForLog, formatErrorForUser, wrapError
- Type guards: isClawdbotError, isError
- Re-exports of domain-specific errors for discoverability
Domain errors remain co-located with their modules for cohesion.
This index provides a single discovery point without creating coupling.
Part of Phase 2: Architecture Cleanup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract cohesive functionality from session-utils.ts (644 LOC) into
focused submodules while maintaining full backwards compatibility:
- session-utils.avatar.ts: Avatar resolution (data URIs, files, URLs)
- session-utils.agents.ts: Agent listing and discovery
- session-utils.store.ts: Store resolution and loading
The main session-utils.ts now orchestrates and re-exports all functions
preserving the existing public API. Core session listing functions
(deriveSessionTitle, loadSessionEntry, classifySessionKey, etc.) remain
in the main file.
Part of Phase 2: Architecture Cleanup
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security Documentation:
- docs/security/threat-model.md: Comprehensive threat model covering
channels, tools, gateway, local files, browser automation, and plugins
- docs/security/data-handling.md: Data handling policy covering storage,
retention, user rights (access, export, delete), and compliance
Doctor Security Check:
- Added credential encryption check to doctor-security.ts
- Warns about unencrypted WhatsApp/Web credentials
This completes Phase 1 Security Hardening (Tasks 1.1-1.6).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pairing Store Hardening:
- Increased pairing code length from 8 to 16 chars (80-bit entropy)
- Added HMAC-SHA256 signatures for store integrity verification
- Added rate limiting (10 attempts/minute per channel)
- Store is automatically reset if signature verification fails
- New ApproveChannelPairingCodeResult type includes rateLimited case
Exec Approval Nonces (Replay Protection):
- Added one-time-use nonces for approval socket requests
- Nonces are generated with 32 bytes of entropy (base64url encoded)
- Nonces expire after 5 minutes with automatic cleanup
- Responses must include matching nonce to be accepted
- Exported functions for testing: generateApprovalNonce, verifyAndConsumeNonce, isNonceValid
Tests:
- 11 pairing store tests (6 new security tests)
- 38 exec-approvals tests (8 new nonce tests)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Support macOS Keychain via `security` command
- Support Linux Secret Service via `secret-tool` (libsecret)
- Fallback to AES-256-GCM encrypted files with PBKDF2 key derivation
- Machine-derived encryption key for file fallback
- Utilities: generateSecureToken, hashSecret, verifySecretHash
- Migration helpers for moving plain-text credentials to secure storage
- Comprehensive test suite (27 tests)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add tiered blocklist (critical/high/medium) for dangerous commands
- Block: rm -rf /, dd to disk, mkfs, halt/reboot, fork bombs, etc.
- Block: sudo, passwd, visudo, iptables, user management
- Warn but allow: command substitution, eval, curl POST, chmod 777
- Integrate blocklist into evaluateShellAllowlist (checked before allowlist)
- Add comprehensive test suite (47 tests)
- Export blocklist utilities for use by other modules
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds `messages` config option to session-memory hook (default: 15).
Fixes filter order bug - now filters user/assistant messages first,
then slices to get exactly N messages. Previously sliced first which
could result in fewer messages when non-message entries were present.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new dmScope option that includes accountId in session keys,
enabling isolated sessions per channel account for multi-bot setups.
- Add 'per-account-channel-peer' to DmScope type
- Update session key generation to include accountId
- Pass accountId through routing chain
- Add tests for new routing behavior (13/13 passing)
Closes#3094
Co-authored-by: Sebastian Almeida <89653954+SebastianAlmeida@users.noreply.github.com>
The MiniMax provider config was updated to use api.minimax.chat
instead of api.minimax.io in PR #3064, but the test expectation
was not updated.
🤖 Generated with Claude Code
- Re-export DirectoryConfigParams and ChannelDirectoryEntry from channels/targets
- Remove unused ChannelDirectoryEntry and resolveDiscordAccount imports
- Fix parseDiscordTarget calls to not pass incompatible options type
- Fix unused catch parameter
Fixes CI build failures on main.
🤖 Generated with Claude Code
Regular Telegram groups (without Topics/Forums enabled) can send
message_thread_id when users reply to messages. This was incorrectly
being used to create separate session keys like '-123:topic:42',
causing each reply chain to get its own conversation context.
Now resolveTelegramForumThreadId only returns a thread ID when the
chat is actually a forum (is_forum=true). For regular groups, the
thread ID is ignored, ensuring all messages share the same session.
DMs continue to use messageThreadId for thread sessions as before.
When sending Discord messages via cron jobs or the message tool,
usernames like "john.doe" were incorrectly treated as channel names,
causing silent delivery failures.
This fix adds a resolveDiscordTarget() function that:
- Queries Discord directory to resolve usernames to user IDs
- Falls back to standard parsing for known formats
- Enables sending DMs by username without requiring explicit user:ID format
Changes:
- Added resolveDiscordTarget() in targets.ts with directory lookup
- Added parseAndResolveRecipient() in send.shared.ts
- Updated all outbound send functions to use username resolution
Fixes#2627
MiniMax has updated their API. The previous configuration used an
incorrect endpoint (api.minimax.io/anthropic) with anthropic-messages
format, which no longer works.
Changes:
- Update MINIMAX_API_BASE_URL to https://api.minimax.chat/v1
- Change API format from anthropic-messages to openai-completions
- Remove minimax from isAnthropicApi check in transcript-policy
This fixes the issue where MiniMax API calls return no results.
Wraps plugin.actions.listActions() in a try/catch so a single
broken channel plugin cannot crash the entire agent boot sequence.
Errors are logged once per plugin+message (deduped) via
defaultRuntime.error() and the call gracefully returns an empty
array instead of propagating the exception.
Fixes: 'Cannot read properties of undefined (reading listActions)'
after the clawdbot→moltbot rename left some plugin state undefined.
- Change MAX_IMAGE_BYTES from 6MB to 5MB to match Anthropic API limit
- Add isImageSizeError() to detect image size errors from API
- Handle image size errors with user-friendly message instead of retry
- Prevent failover for image size errors (not retriable)
Fixes#2271
Add test cases to verify:
- baseUrl is inherited from provider when model does not specify it
- api is inherited from provider when model does not specify it
- model-level api takes precedence over provider-level api
- both baseUrl and api can be inherited together
Co-Authored-By: Claude (claude-opus-4.5) <noreply@anthropic.com>
When using custom providers with inline model definitions, the baseUrl
and api properties from the provider config were not being passed to
the individual models. This caused requests to be sent to the wrong
endpoint or with the wrong API format.
Changes:
- buildInlineProviderModels now copies baseUrl from provider to models
- buildInlineProviderModels now inherits api from provider if not set on model
- resolveModel fallback path now includes baseUrl from provider config
Co-Authored-By: Claude (claude-opus-4.5) <noreply@anthropic.com>