# 🚀 CodeBuddy Code v2.97.0 Release

## ✨ New Features

### Complete Keybindings System

Implemented a keybindings system referencing the CodeBuddy Code architecture, supporting context conditions, chord sequences (e.g. Ctrl+X Ctrl+K), and user-defined overrides.

- Configuration file: `~/.codebuddy/keybindings.json`
- 16 contexts (Global / Chat / Terminal / Autocomplete, etc.) with 60+ actions
- `/keybindings` slash command for quick management
- Web UI adds visual configuration (grouped by context, search, recording, real-time conflict detection)
- REST API: `/api/v1/keybindings` (GET/PUT/POST reset/POST validate)

### Skill / Subagent Frontmatter Hooks

Aligned with CodeBuddy Code behavior, the `hooks:` field is now supported in the YAML frontmatter of `.codebuddy/agents/*.md` and `.codebuddy/skills/*/SKILL.md`, and is automatically registered and cleaned up during the sub-agent / fork skill lifecycle.

- Supports four hook types: `command` / `prompt` / `agent` / `http`
- `once: true` for automatic removal, with event matcher semantics
- **Default Safety Gate**: Frontmatter hooks from non-product built-in sources are disabled by default (including local and plugin marketplace), and require enabling `allowUntrustedFrontmatterHooks: true` in `settings.json` to take effect

### Hook Events Fully Aligned with CodeBuddy Code

Added 20+ hook events covering tool failures, sub-agent lifecycle, task management, permission approvals, file watching, and more:

- **Lifecycle**: PostToolUseFailure / SubagentStart / StopFailure / PostCompact / ConfigChange / InstructionsLoaded
- **Permissions and Tasks**: PermissionRequest / PermissionDenied (can intercept approvals), TaskCreated / TaskCompleted, TeammateIdle, Setup
- **File Watching**: FileChanged (declares watchPaths), CwdChanged (triggered on cwd change)
- **New Hook Types**: `http` (POST to any URL), `agent` (reuses prompt path)
- **New Fields**: `if` (matches by tool name/parameters), `shell` (switch to PowerShell), `once` (no longer triggers after success), `asyncRewake`, `allowedEnvVars`, `statusMessage`
- **Async Protocol**: Hook output `{"async": true, "asyncTimeout": N}` immediately releases as fire-and-forget

### Variable Placeholders for Skills / Commands / Subagents

`.md` files now support variable placeholder substitution: `${CODEBUDDY_PLUGIN_ROOT}` / `${CODEBUDDY_SKILL_DIR}` / `${CODEBUDDY_SESSION_ID}` and any uppercase environment variables, with `${MY_ENV_VAR:-default}` default value syntax. Unset placeholders are preserved as-is to avoid silently losing configuration.

### Third-Party Plugin Marketplace Auto-Update

Added the `autoUpdateThirdPartyMarketplaces` product configuration and the `CODEBUDDY_AUTO_UPDATE_THIRD_PARTY_MARKETPLACES` environment variable, supporting global enabling of third-party plugin marketplace auto-updates. The marketplace configuration entry adds an optional `autoUpdate` field for individual control.

### Configurable Remote Gateway Task Timeout

The default timeout for the `/api/v1/runs` endpoint has been raised from 10 minutes to **30 minutes**, so long-running tasks are no longer forcibly interrupted:

- New `gateway.runTimeoutMs` settings configuration (milliseconds)
- New HTTP header `X-Codebuddy-Run-Timeout` for single-request override
- Set to 0 or negative to disable timeout protection

### Web UI PWA Auto-Detects New Versions

After releasing a new version, already-opened Web UI tabs no longer require a manual hard refresh:

- Automatically asks the backend whether a new Service Worker is available every 15 minutes
- Automatically refreshes to the new version when the conversation is idle
- During an ongoing conversation, a toast pops up retaining the "Refresh Now" button; subscribed run state will auto-refresh after the Agent becomes idle

### UE Projects Automatically Exclude Monorepo Noise Directories

When `*.uproject` is detected in the cwd, Grep / Glob automatically applies `!Intermediate/` `!DerivedDataCache/` `!Saved/` `!Binaries/` `!Build/` `!.vs/` exclusions to avoid build artifacts of Unreal Engine projects (typically 100K+ source files / 3M+ total files) polluting search results. This can be disabled via `settings.disableUEAutoExclude: true`. Grep content search adds `--max-columns 500` to prevent single-line MB-sized content from flooding stdout.

### Desktop Filesystem ACP Methods

Implemented the complete `fs/*` methods (list / read / write / exists / makeDir / remove / rename / getInfo / watchDir / unwatch) in ACP StreamManager, enabling the WorkBuddy Desktop "All Files" tab to work properly.

## 🔧 Improvements

- **PowerShell Multi-Layer Security Defense**: CLM type whitelist (~90 types), Git security protection (bare repo / NTFS 8.3 / archive extractor), dangerous Cmdlet classification (7 sets + 120+ aliases), destructive command UI warnings (16 patterns), Unicode dash support
- **ACP Connection Stability**: GET SSE connection 30-second heartbeat to prevent reverse proxy (cloudflared / nginx) recycling; waits for history writes to complete on connection close to prevent JSONL log truncation
- **Bash Tool Timeout Hint Made Dynamic**: The "max timeout" in the tool description was previously hardcoded to 600000ms; now it is dynamically injected to stay consistent with the runtime's actual clamp value
- **TUI Ctrl+F / Ctrl+B Cursor Navigation**: Supports bash readline-style left/right one-character movement, consistent with existing Ctrl+A / Ctrl+E / Ctrl+K / Ctrl+U; emoji multi-byte character movement is correct
- **Web UI Canvas-Embedded Terminal Text Selection**: After a tile is focused, the overlay passes pointerdown through to xterm to support select-and-copy; middle / right click / Space + left click still drive canvas panning
- **Channel Permission deny_and_exit_plan**: WeChat / WeChat Work users can exit Plan mode by replying `q`; the ExitPlanMode tool adds a dedicated prompt
- **Request Purpose Tagging**: New `X-Agent-Purpose` HTTP header to add classification labels to different types of LLM requests, enabling Langfuse trace analysis
- **Image Compression Interceptor**: Uniformly compresses base64 images sent by users to a 2000px long edge, ensuring images from ACP / TUI / plugin-chat sources all undergo size optimization
- **Worktree Directory Switching**: After creating or reusing a worktree, tries to enter the relative subdirectory corresponding to the current directory whenever possible
- **Unified Session API**: Merged `listWorkspaces` and `listAcrossProjects` into a unified `GET /api/v1/sessions` endpoint, with `cwd` query parameter support
- **Auto-Recovery for Model Permission Errors**: When the backend returns "model unavailable", the product configuration is automatically refreshed and the latest available model list is displayed
- **Removed Legacy Models and Refreshed Credit Coefficients**: Removed the HY 2.0 series (3 models) and GPT-5.2/5.1, totaling 4 legacy models; refreshed model credits per the latest official pricing table (iOA / China Edition / Cloud-Hosted Edition)
- **Plugin Loading Concurrency and Caching**: Introduced concurrency limits for marketplace plugin list / metadata / component loading to avoid startup jitter; added marketplace plugin list caching and load deduplication
- **Automation Task Langfuse Tags**: Requests triggered by scheduled tasks automatically carry the `automation` tag for easy filtering

## 🐛 Bug Fixes

### ACP Protocol and Stability

- **`/clear` Separator Lost After Restart**: Fixed an issue where `/clear` separators inserted in CBC / WorkBuddy Desktop sessions disappeared after restart or loadSession replay, along with the resulting 400 errors
- **`/compact` Effective in IM Scenarios**: WorkBuddy Desktop IM's `/compact` / `/总结` previously had no effect; now compaction is invoked via `_meta` short-circuit
- **Cancel Barrier**: If a new `session/prompt` arrives the moment a cancel completes, it would be treated as a new conversation start; added a 500ms cancel barrier
- **Cancel Marker Leak**: When prompt terminal state and `session/cancel` happen simultaneously, the pending cancellation marker was not consumed, causing subsequent AskUserQuestion rounds to be misjudged as canceled
- **Streaming Reply Repeats Reasoning Content**: Fixed WorkBuddy chat streaming reply repeatedly outputting reasoning content
- **AskUserQuestion Shows "Unanswered"**: In ACP mode, the UI displayed "Unanswered" after the user answered AskUserQuestion
- **AskUserQuestion Misjudged as "Refused to Answer"**: The approval signal arrived before the tool execution path established a waiter, causing the answer to be discarded
- **Session Lookup Race Condition**: `session/prompt` now uses `getRuntimeSession` to prioritize active sessions, avoiding "Session not found"
- **Sessions Inherit CLI Startup Parameters**: Sessions created via ACP in `--serve` mode did not inherit `--permission-mode` / `--model` and other parameters
- **`session/load` Timeout**: Timeouts occurred in some Windows environments; added a 25s fallback at the protocol entry layer
- **Model Switch Not Effective**: `unstable_setSessionModel` now writes the new model into the runtime session immediately, no longer relying solely on subscription side effects
- **No Longer Exposes Built-in Commands as Skills**: `/clear` `/help` `/model` `/theme` `/status` `/resume` `/rename` are no longer mixed into the `Skill` tool list

### Context Compaction (Compact)

- **Auto-Cancel Loop**: Compaction would falsely appear "auto-canceled" in some scenarios and then immediately retrigger; the compaction call wait limit was relaxed from 60 seconds to 20 minutes
- **Residual XML Tags**: Residual `</conversation_history_summary>` tag remained when tasks ended abnormally
- **Summary and User Message Misaligned**: In request-level auto pre-compaction scenarios, the compaction summary and the original user message were misaligned in history
- **Degenerate Summary**: After auto-compaction of long sessions, when there was insufficient effective new content, compaction could still trigger again and generate an invalid summary
- **History View Stuck After Failure**: After a failure/cancellation, retriggering compaction was still stuck
- **Timeout Deadlock and Cancellation**: Sub-agent compact state machine would deadlock after timeout; the cancellation signal was swallowed when the user actively canceled
- **Custom Model Auto-Compaction Window**: Falls back to the `CODEBUDDY_AUTO_COMPACT_WINDOW` fallback window when `maxInputTokens` is not configured
- **SDK Mode Auto-Compaction Disconnect**: Compaction output leaked to stdout in SDK / headless mode causing disconnection
- **Auto-Compaction Renders Raw XML**: The chat interface rendered raw `<conversation_history_summary>` tags; now uses the same rendering as `/compact`
- **Failure Preserves User Message**: After auto pre-compaction before sending fails, the user message is preserved and a clear failure prompt is shown
- **History `Unknown content` Error**: Continuing a conversation from history could throw `Unknown content` and cause interruption

### Models and Request Handling

- **PTL Context Overflow Recovery**: Added a fallback mechanism that precisely truncates history by API turn, covering common model error messages
- **Empty Stream Auto-Retry**: Recognizes "empty stream" scenarios where the upstream gateway sends only placeholder/heartbeat frames before disconnecting, and auto-recovers
- **Request Body Size Limit Recovery**: Explicitly sets `maxBodyLength: Infinity` on axios to avoid follow-redirects' default 10MB limit intercepting locally
- **`Tool X not found` Error Handling**: Errors no longer carry agent names with product implementation details; `ModelBehaviorError` no longer pops a client error dialog and instead ends the round via `end_turn`
- **Custom Model Gzip Detection**: Fixed an issue where the `custom-local:` prefix stripping caused product.models configuration to fail to match
- **Custom Model Loading 400**: Supports both top-level array and object-wrapped formats of models.json

### History and Sessions

- **First User Message Lost**: The user's first message containing hidden context disappeared in the UI
- **Model Error Rendered as Assistant Reply**: Rounds interrupted by model errors (6004/429) were rendered as normal answers
- **Orphaned tool_call Replay**: Skips replay for interrupted tool calls and injects a system notification
- **Task List Display in Old Sessions**: Sessions migrated from older versions rendered an empty task list after restoration
- **Image Message Title Pollution**: Local image paths leaked in history replay and session title generation scenarios
- **Plan Mode Permission Recovery**: `prePlanPermissionMode` was not correctly passed when starting Plan mode from the Desktop side

### Tools and Permissions

- **Restored Grep/Glob Tool Registration**: Grep/Glob were previously incorrectly removed from 5 product.json files, causing fallback to Bash+rg
- **`--disallowedTools` Subcommand Rules**: Rules with subcommands (e.g., `Bash(pkill:*)`) were removing the entire tool
- **Tool Filter Bypass Vulnerability**: ToolSearch lookup mode and DeferExecuteTool did not check tool availability
- **Glob/Grep Empty Result Hint**: Returns meaningful text hints instead of empty arrays
- **rm Bulk Deletion Risk Level**: Raised from MEDIUM to HIGH to ensure bulk deletion on the IM side triggers user confirmation
- **Sandbox strip_write False Success**: Silently dropped writes/deletions did not trigger the elevation UI

### Configuration Directory

- **Bash Sandbox Configuration Directory Path**: The Bash sandbox whitelist was ineffective under custom `CODEBUDDY_CONFIG_DIR` directories
- **Hardcoded Paths in Prompt Templates**: TeamCreate / TeamDelete / statusline-setup tool description templates now render the actual directory via `{{codebuddyHome}}`
- **Hardcoded Paths in UI Panels**: Permissions / Agents / Skills / Memory panels display real paths
- **Sandbox Toggle Storage Tier**: The Desktop sandbox toggle changed from persistent to in-memory (session-level) to avoid polluting workspace directories

### Plugin Marketplace

- **MCP Static Authorization Overridden by OAuth**: Fixed an issue where the OAuth flow was still triggered when `headers.Authorization` was explicitly configured
- **Marketplace Duplicate Names**: Name collisions resulted in two entries with the same name that could not be deleted
- **Marketplace Duplicate Add Error**: Changed to automatically trigger the update flow
- **Marketplace Update Cache Not Refreshed**: `lastUpdated` time was not updated after `updateMarketplace`
- **GithubMarketplace Directory Name Alignment**: Non-standard repo URL directory names were inconsistent with manifest.name
- **Git Unavailable ZIP Fallback**: Adding a plugin marketplace failed in Windows environments without Git installed
- **Built-in Suite Marketplace ZIP Distribution**: The default suite marketplace had no content; adding the marketplace failed
- **Plugin Sub-Agent Description Refresh**: Descriptions were not refreshed in time after loading or switching plugin sub-agents
- **Skill Scan Dangling Symlinks**: Previously caused the entire directory scan to abort

### Windows Compatibility

- **PowerShell Office Automation**: Excel / Word / PowerPoint / Outlook creation was incorrectly intercepted by security policies
- **PowerShell Command Wrapping**: When `rawCommand=true`, skips the bash wrapper to avoid backslashes/backticks being swallowed
- **Black Window Pop-up**: conhost / Git Bash black windows popped up during `--bg` background sessions and daemon startup
- **Plugin Commands Not Displayed**: `CODEBUDDY_PLUGIN_DIRS` now uses `path.delimiter` to avoid drive letters being treated as separators
- **Bash Tool Chinese Garbled Text**: Reassembles UTF-8 multi-byte sequences across chunks; injects `PYTHONUTF8=1` on Windows

### Others

- **Daemon Port Race**: `EADDRINUSE` startup failure or long connection blocking on restart
- **MessageQueueDeferredDispatch (Mode B)**: Agent queue messages could not be sent successfully; "send immediately" messages were lost
- **Team Message Real-Time Delivery**: While the leader was busy, member SendMessages were stuck in the message queue and not consumed
- **Playbook Team Spinner**: The agent on the left kept spinning after task completion
- **Expert Built-in Skills Invisible**: Skill / SlashCommand / ToolSearch tool description caches were not invalidated after `rebuildAgents` completed
- **Session Title and Summary Triggers**: Ensures title updates, content summarization, and pre-compaction refresh take effect as expected
- **ImageGen / ImageEdit Cancellation Support**: Image generation requests continued executing after cancellation
- **Self-Hosted Deployment Detection**: Configurations with enterprise endpoints but actually cloud-hosted were incorrectly marked as Self-Hosted
- **`anydev` Remote IDE `/ide` Command**: Added `CODEBUDDY_IDE_PORT` / `CODEBUDDY_IDE_HOST` / `CODEBUDDY_IDE_SKIP_VALID_CHECK` environment variables
- **Web UI Editor Save Empties File**: The frontend `writeFile` did not explicitly set Content-Type and was consumed by body-parser
- **Gateway CORS Static Resources**: Same-origin IP access to static resources was incorrectly intercepted when the CORS whitelist was enabled
- **Read Tool Image Return Format**: Returns image content block format
- **Worktree Relative cwd**: When reusing a worktree, the relative directory was not entered correctly

## 📝 Documentation Updates

- **Deprecated sandboxing.md Documentation**: Related links now point to bash-sandboxing.md
