ShellDenyGroups was defined in SystemPromptConfig but lacked full propagation
through parser, Loop fields, context injection, and system prompt population.
Per-agent overrides from other_config JSONB had zero runtime effect.
Changes:
- agent_store.go: Add ParseShellDenyGroups() to extract overrides from JSONB
- loop_types.go: Add shellDenyGroups field to Loop and LoopConfig, wire in NewLoop
- resolver.go: Wire agent-parsed shell deny groups into LoopConfig
- loop.go: Inject shellDenyGroups into context via store.WithShellDenyGroups
- loop_history.go: Populate ShellDenyGroups in system prompt config
- message_test.go: Fix macOS symlink path normalization in test expectations
Fixes test failures on macOS where /var/folders symlinks to /private/var/folders.
MessageTool.parseMediaPath() was hardcoded to only allow files in /tmp/,
while all other filesystem tools (read_file, write_file, edit, exec) use
workspace-aware resolvePath() with restrict_to_workspace enforcement.
This meant agents could create files in their workspace via write_file
but couldn't send them as attachments — only /tmp/ files from
create_image/create_audio worked.
Replace parseMediaPath() with resolveMediaPath() that:
- Reuses resolvePath() for consistent security (symlink, hardlink, traversal)
- Honors per-agent workspace + restrict_to_workspace from context
- Still allows /tmp/ as fallback (for create_image, create_audio, etc.)
- Supports relative paths resolved against workspace
- Updates tool description so LLM knows about MEDIA: prefix
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
- Fix CI: use %s for json.Number in e2e test (was %d)
- Fix path traversal in parseMediaPath: restrict to os.TempDir()
- Add 25MB file size limit (checkFileSize) before upload reads
- Drain stale uploadCallbacks on Listener.reset() to prevent leaks
- Split send.go (688 LOC) into send.go, send_image.go, send_file.go, send_helpers.go
- Add unit tests for parseMediaPath (12 cases incl. traversal attacks)