* The code compiles successfully. The fix is complete.
To summarize: The issue was that the `try_stop` function in `crates/services/src/services/container.rs:348` was stopping **all** running execution processes when the user pressed the stop button. This included the dev server process. The fix adds a check to skip processes with `run_reason == ExecutionProcessRunReason::DevServer`, so the dev server continues running while other processes (like the coding agent) are stopped.
* All done. Here's a summary of the changes:
**Changes made:**
1. **`crates/services/src/services/container.rs`:**
- Modified `try_stop` to accept an `include_dev_server: bool` parameter - when `false`, it skips dev server processes
- Updated `delete` method to call `try_stop(&task_attempt, true)` - when deleting a container, all processes including dev server are stopped
- Removed the unused `stop_task_processes` method
2. **`crates/server/src/routes/task_attempts.rs`:**
- Updated `stop_task_attempt_execution` (stop button) to call `try_stop(&task_attempt, false)` - dev server keeps running
- Updated the retry flow to call `try_stop(&task_attempt, false)` - dev server keeps running during retry
* Cleanup script changes for task attempt 51e0f037-850b-4739-8675-16819c3a5695
## Summary of Removed Unused Methods
### `crates/db/src/models/task.rs` (2 methods)
- `Task::find_by_id_and_project_id` (was at line 241)
- `Task::exists` (was at line 461)
### `crates/db/src/models/project.rs` (2 methods)
- `Project::find_by_remote_project_id` (was at line 152)
- `Project::exists` (was at line 368)
### `crates/db/src/models/task_attempt.rs` (1 method)
- `TaskAttempt::find_by_task_id_with_project` (was at line 266)
### `crates/db/src/models/execution_process.rs` (3 methods)
- `ExecutionProcess::count_later_than` (was at line 172)
- `ExecutionProcess::delete_by_task_attempt_id` (was at line 482)
- `ExecutionProcess::set_restore_boundary` (was at line 505)
### `crates/db/src/models/executor_session.rs` (5 methods)
- `ExecutorSession::find_by_id` (was at line 37)
- `ExecutorSession::find_by_task_attempt_id` (was at line 83)
- `ExecutorSession::find_by_session_id` (was at line 107)
- `ExecutorSession::update_prompt` (was at line 199)
- `ExecutorSession::delete_by_task_attempt_id` (was at line 241)
### `crates/db/src/models/execution_process_logs.rs` (1 method)
- `ExecutionProcessLogs::serialize_logs` (was at line 51)
**Total: 14 unused methods removed**
The build passes successfully (`cargo check --workspace`), confirming all changes are valid.
* fix: skip watching heavy directories to avoid memory leak
* fix: reduce memory usage in filesystem watcher for pnpm projects
Use gitignore-aware directory collection to prevent OS-level watchers
from being set up on heavy directories like node_modules.
Changes:
- Use WalkBuilder's git_ignore(true) to respect .gitignore when collecting watch directories
- Use NonRecursive watch mode for each directory instead of single Recursive watch
- Simplify ALWAYS_SKIP_DIRS to only contain .git (not in .gitignore but should be skipped)
This fixes high memory usage when running vibe-kanban on pnpm-managed
repositories, which contain many symlinks in node_modules.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: simplify filesystem watcher error handling and fix clippy warnings
- Remove debug logs that were added during development
- Fail fast on watch errors instead of continuing in a partially broken state
- Collapse nested if statements to satisfy clippy::collapsible_if
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: check only parent directories in path_allowed
Only check parent directory names against ALWAYS_SKIP_DIRS since
should_skip_dir is meant for directories, not file names.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add watch directories changes
* Stop leaking filesystem watcher
Use weak references so the background thread exits once the diff stream releases the debouncer.
* Memoize ignored-descendant scan
Cache per-directory results so collecting watch targets stays linear.
* Improve watcher gitignore classification
Use real metadata when available, fall back to the old heuristic only when the file is already gone, and document the limitation.
* Handle directory renames in watcher
* Deduplicate watch directories more efficiently
Sort once and do a single sweep instead of quadratic filtering.
* Document gitignore watcher limitation
* Cascade watcher removal on directory delete
Drop all descendant watchers when a parent directory disappears so stale handles don’t linger.
* Watch subdirectories when new directories are added
Track recursive parent watchers so we skip redundant child watches and prune them when a parent becomes recursive.
* Always ignore node_modules
* Use a high-performance line count diff implementation
The `similar` diff stat implementation was causing cpu spikes of up to 600% over 10 seconds.
* exclude node_modules from git diff commands
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Solomon <abcpro11051@disroot.org>
* I've completed the implementation. Here's a summary of the changes made:
## Summary
### Backend (Rust)
1. **`crates/services/src/services/config/versions/v8.rs`**
- Added two new config fields:
- `pr_auto_description_enabled: bool` - defaults to `false`
- `pr_auto_description_prompt: Option<String>` - defaults to `None`
2. **`crates/server/src/routes/task_attempts.rs`**
- Added `auto_generate_description: bool` field to `CreateGitHubPrRequest`
- Added `DEFAULT_PR_DESCRIPTION_PROMPT` constant with the default prompt
- Added `trigger_pr_description_follow_up()` helper function that:
- Gets the custom prompt from config or uses default
- Replaces `{pr_number}` and `{pr_url}` placeholders
- Triggers a follow-up (or initial if no session) coding agent execution
- Modified `create_github_pr()` to call the follow-up trigger after successful PR creation
### Frontend (TypeScript/React)
3. **`frontend/src/components/dialogs/tasks/CreatePRDialog.tsx`**
- Added `autoGenerateDescription` state, initialized from `config.pr_auto_description_enabled`
- Added checkbox to toggle auto-generate PR description
- Included `auto_generate_description` in the API call payload
4. **`frontend/src/pages/settings/GeneralSettings.tsx`**
- Added "Pull Requests" Card section with:
- Checkbox to enable/disable auto-generate by default
- Textarea for custom prompt override
5. **Translation files**
- Added `autoGenerateLabel` to `tasks.json`
- Added `pullRequests` section to `settings.json`
6. **`shared/types.ts`** - Auto-generated with new types
### Key Features
- Toggle in PR creation dialog, defaulting to the global config setting
- Settings page for configuring default behavior and custom prompt
- Placeholders `{pr_number}` and `{pr_url}` for custom prompts
- Uses the same executor profile as the original task attempt
- Graceful error handling (warns but doesn't fail PR creation if follow-up fails)
* Cleanup script changes for task attempt 46e66dfc-f608-47a4-baca-e38399d2da15
* Done! I've updated the placeholder text in `settings.json` to show the actual default prompt. Now users can see exactly what prompt the AI agent will use by default, and they know what they're customizing when they enter a custom prompt.
The placeholder now shows:
```
Update the GitHub PR that was just created with a better title and description.
The PR number is #{pr_number} and the URL is {pr_url}.
Analyze the changes in this branch and write:
1. A concise, descriptive title that summarizes the changes
2. A detailed description that explains:
- What changes were made
- Why they were made (based on the task context)
- Any important implementation details
Use `gh pr edit` to update the PR.
```
I also updated the helper text to mention the placeholder variables (`{pr_number}` and `{pr_url}`) so users know what variables they can use in their custom prompts.
* Cleanup script changes for task attempt 46e66dfc-f608-47a4-baca-e38399d2da15
* Done! Updated the label to "Ask AI agent to generate a better PR description" as requested.
* All done! The refactoring is complete:
**Summary of changes:**
1. **Created `crates/server/src/routes/task_attempts/pr.rs`** - New submodule containing all PR-related code:
- Types: `CreateGitHubPrRequest`, `CreatePrError`, `AttachPrResponse`, `PrCommentsResponse`, `GetPrCommentsError`
- Constants: `DEFAULT_PR_DESCRIPTION_PROMPT`
- Functions: `trigger_pr_description_follow_up`, `create_github_pr`, `attach_existing_pr`, `get_pr_comments`
2. **Updated `crates/server/src/routes/task_attempts.rs`** - Added `pub mod pr;` and updated router to use `pr::` prefix for PR routes
3. **Updated `crates/server/src/bin/generate_types.rs`** - Fixed all paths to reference `pr::` submodule for the PR-related types
Both backend (cargo check) and frontend (TypeScript) compile successfully, and TypeScript types have been regenerated.
* Cleanup script changes for task attempt 46e66dfc-f608-47a4-baca-e38399d2da15
* Done! I've updated the default PR description prompt in both locations:
1. **`crates/server/src/routes/task_attempts/pr.rs`** - Updated `DEFAULT_PR_DESCRIPTION_PROMPT` constant
2. **`frontend/src/i18n/locales/en/settings.json`** - Updated `pullRequests.customPrompt.placeholder`
The changes are:
- Title should now be postfixed with "(Vibe Kanban)"
- Description should include a note at the end: "This PR was written using [Vibe Kanban](https://vibekanban.com)"
* Done! I've updated `pr_auto_description_enabled` to default to `true` in three places:
1. Added `default_pr_auto_description_enabled()` function that returns `true`
2. Updated the `#[serde(default)]` attribute to use this function
3. Updated the `from_v7_config` migration to set it to `true`
4. Updated the `Default` impl to set it to `true`
* All done! I've added i18n translations for the PR auto-description feature to all supported languages:
**settings.json** - Added `pullRequests` section with:
- `title`, `description`
- `autoDescription.label`, `autoDescription.helper`
- `customPrompt.label`, `customPrompt.placeholder`, `customPrompt.helper`
**tasks.json** - Added `autoGenerateLabel` key
Languages updated:
- Spanish (es)
- Japanese (ja)
- Korean (ko)
- Simplified Chinese (zh-Hans)
* Update frontend/src/i18n/locales/en/tasks.json
Co-authored-by: Gabriel Gordon-Hall <gabriel@bloop.ai>
* Done! I've implemented the UX improvement from the PR review:
1. **Moved the auto-generate checkbox** to the top of the form (above title and description)
2. **Added `disabled` prop** to both the title Input and description Textarea when `autoGenerateDescription` is true
3. **Added greyed-out styling** (`opacity-50 cursor-not-allowed`) to visually indicate the fields are disabled
The new field order is:
1. Auto-generate checkbox
2. Title input (disabled when checked)
3. Description textarea (disabled when checked)
4. Base branch selector
5. Draft checkbox
* All done! I've:
1. **Made `DEFAULT_PR_DESCRIPTION_PROMPT` public** in `pr.rs`
2. **Exported the constant to `shared/types.ts`** via `generate_types.rs`:
- Imported the constant from the pr module
- Added code to append `export const DEFAULT_PR_DESCRIPTION_PROMPT = \`...\`;` to the generated types
3. **Updated `GeneralSettings.tsx`** to import and use the constant directly as the placeholder
4. **Removed the duplicate `placeholder` key** from all i18n `settings.json` files (en, es, ja, ko, zh-Hans)
The default prompt is now defined in a single place (the Rust backend) and exported to TypeScript, eliminating duplication across all i18n files.
* Cleanup script changes for task attempt 46e66dfc-f608-47a4-baca-e38399d2da15
* Done! I've implemented the two-step UX for the custom prompt:
1. **Updated `GeneralSettings.tsx`**:
- Replaced the always-visible textarea with a "Use custom prompt" checkbox
- When checked, pre-fills the textarea with `DEFAULT_PR_DESCRIPTION_PROMPT`
- When unchecked, sets `pr_auto_description_prompt` to `null` (reverts to default)
- Textarea only visible when custom prompt is enabled
2. **Updated i18n files** (all 5 languages):
- Replaced `label` with `useCustom` key
- Updated `helper` text to remove "Leave empty to use the default" since that's now handled by the checkbox
- Added translations:
- **en**: "Use custom prompt"
- **es**: "Usar prompt personalizado"
- **ja**: "カスタムプロンプトを使用"
- **ko**: "사용자 정의 프롬프트 사용"
- **zh-Hans**: "使用自定义提示"
* Done! The custom prompt UX has been updated:
- **Textarea is now always visible** showing the current prompt (default or custom)
- **When "Use custom prompt" is unchecked**: textarea shows `DEFAULT_PR_DESCRIPTION_PROMPT` but is disabled/read-only with greyed-out styling
- **When "Use custom prompt" is checked**: textarea becomes editable, pre-filled with the default prompt for customization
This gives users visibility into what prompt will be used even when using the default, while still allowing them to customize it by checking the checkbox.
* Cleanup script changes for task attempt 46e66dfc-f608-47a4-baca-e38399d2da15
* Done! The fix has been applied. Now when the "Use custom prompt" checkbox is checked, users can:
- Clear all the text in the textarea to start from scratch
- The text no longer automatically reverts to the default prompt when emptied
---------
Co-authored-by: Gabriel Gordon-Hall <gabriel@bloop.ai>
* All implementation steps are complete. Here's a summary of what was implemented:
Implemented auto-linking of subtasks when creating tasks with 6 changes:
1. **`crates/db/src/models/task_attempt.rs`** - Added `find_by_branch()` query to look up task attempts by branch name within a project
2. **`crates/db/src/models/task.rs`** - Added:
- `Clone` derive to `CreateTask` struct
- `with_parent_from_branch()` helper method on `CreateTask` for fluent branch-based parent resolution
- `update_parent_task_attempt()` method on `Task` to update parent linkage for existing tasks
3. **`crates/server/src/routes/tasks.rs`** - Updated `create_task_and_start()` to use `with_parent_from_branch()` helper before creating the task
4. **`crates/server/src/routes/task_attempts.rs`** - Updated `create_task_attempt()` to link existing tasks to parent attempts when `base_branch` matches an existing attempt's branch
5. **`crates/server/src/mcp/task_server.rs`** - Updated MCP `create_task` to automatically set `parent_task_attempt` from the current context's `attempt_id`
6. **`crates/db/.sqlx/`** - Updated SQLx query cache with the new queries
* Cleanup script changes for task attempt 3bcb8f0d-6655-4b34-9cd2-c3c731795b78
* All implementation steps are complete. Here's a summary of what was implemented:
## Summary
Auto-linking of subtasks when creating tasks is now implemented for all three scenarios:
1. **MCP create_task** (`task_server.rs:404-432`): When an AI agent creates a task via MCP while working in a worktree, the new task automatically becomes a subtask of the current attempt (uses `McpContext.attempt_id`)
2. **Branch-based targeting**:
- `create_task_and_start` (`tasks.rs`): Uses `with_parent_from_branch` helper to auto-link when `base_branch` matches an existing attempt
- `create_task_attempt` (`task_attempts.rs`): Updates existing task's parent when creating an attempt with a matching `base_branch`
3. **Rebase** (`task_attempts.rs:1249-1257`): When rebasing a task attempt onto another attempt's branch, the task's `parent_task_attempt` is updated to point to that attempt
### Files modified:
- `crates/db/src/models/task_attempt.rs` - Added `find_by_branch` query
- `crates/db/src/models/task.rs` - Added `Clone` derive, `with_parent_from_branch` helper, `update_parent_task_attempt` method
- `crates/server/src/routes/tasks.rs` - Updated `create_task_and_start`
- `crates/server/src/routes/task_attempts.rs` - Updated `create_task_attempt` and `rebase_task_attempt`
- `crates/server/src/mcp/task_server.rs` - Updated MCP `create_task`
* Cleanup script changes for task attempt 3bcb8f0d-6655-4b34-9cd2-c3c731795b78
* All 8 steps are now complete. Here's a summary of the implementation:
## Summary
Added auto-linking of subtasks in the `change_target_branch` endpoint (`task_attempts.rs:1047-1055`). When a user changes a task attempt's target branch to match another attempt's branch, the task automatically becomes a subtask of that attempt.
The full implementation now covers all 4 scenarios:
1. **MCP create_task** - Links via `McpContext.attempt_id`
2. **Branch-based targeting** - Links in `create_task_and_start` and `create_task_attempt` via `with_parent_from_branch`
3. **Rebase** - Links in `rebase_task_attempt` after successful git rebase
4. **Change target branch** - Links in `change_target_branch` after updating target_branch (newly added)
* Done. Removed `from_title_description` helper from `task.rs` and updated `task_server.rs` to construct `CreateTask` directly with all fields set correctly. All checks pass.
* Implementation is complete. Let me provide a summary of the changes made:
## Summary
I've implemented tag expansion for the MCP server. Here are the changes:
### Files Modified
1. **`crates/server/Cargo.toml`** - Added `regex = "1"` dependency
2. **`crates/server/src/mcp/task_server.rs`** - Three changes:
- Added imports for `Tag` and `Regex`
- Added `expand_tags()` helper function that:
- Finds all `@tagname` patterns using regex `@([^\s@]+)`
- Fetches tags from `/api/tags` endpoint
- Replaces each `@tagname` with the tag's content
- Returns original text if tag not found or on error
- Updated `create_task` to expand tags in description before creating
- Updated `update_task` to expand tags in description before updating
- Updated tool descriptions to mention tag expansion support
### How It Works
When an AI agent calls `create_task` or `update_task` with a description containing `@tagname` (e.g., `"Please implement this feature @requirements"`), the MCP server will:
1. Parse the description for `@tagname` patterns
2. Fetch all available tags from the backend API
3. Replace each `@tagname` with the corresponding tag's `content`
4. Save the task with the expanded description
If a tag is not found, the `@tagname` is left as-is. If there's a network error, the original text is preserved to ensure task creation doesn't fail.
* Update crates/server/src/mcp/task_server.rs
Co-authored-by: Solomon <abcpro11051@disroot.org>
* Update crates/server/src/mcp/task_server.rs
Co-authored-by: Solomon <abcpro11051@disroot.org>
---------
Co-authored-by: Solomon <abcpro11051@disroot.org>
* The implementation is complete. Here's a summary of the changes:
## Summary
Added notification sound when approval is needed, using the same notification system as task finalization.
**Files modified:**
1. **`crates/services/src/services/approvals/executor_approvals.rs`**
- Added `config: Arc<RwLock<Config>>` field to `ExecutorApprovalBridge`
- Added imports for `Config`, `NotificationService`, and `RwLock`
- Added notification call in `request_tool_approval()` after creating the approval request
2. **`crates/local-deployment/src/container.rs`**
- Passed `self.config.clone()` to `ExecutorApprovalBridge::new()`
When an approval is requested, the notification will display:
- **Title:** "Approval Needed"
- **Message:** "Tool '{tool_name}' requires approval"
The notification uses the user's configured sound file and respects their notification settings (sound enabled/disabled, push enabled/disabled).
* Cleanup script changes for task attempt af6bac2d-a3ba-4c6a-ae35-3a54bd05212f
* Done! Here's a summary of the refactored implementation:
## Summary
Refactored `NotificationService` to hold config internally and added approval notification sound:
**Files modified:**
1. **`crates/services/src/services/notification.rs`**
- Added `config: Arc<RwLock<Config>>` field
- Added `new(config)` constructor
- Changed `notify` and `notify_execution_halted` from static to instance methods
- Added internal `send_notification` helper method
2. **`crates/services/src/services/container.rs`**
- Updated `finalize_task` trait method to accept `&NotificationService` instead of `&Arc<RwLock<Config>>`
- Removed unused `Config` import
3. **`crates/local-deployment/src/container.rs`**
- Added `notification_service: NotificationService` field to `LocalContainerService`
- Initialize service in `new()` with config
- Updated all `finalize_task` calls to pass `&self.notification_service`
- Updated `ExecutorApprovalBridge::new()` to pass `notification_service`
4. **`crates/services/src/services/approvals/executor_approvals.rs`**
- Replaced `config: Arc<RwLock<Config>>` with `notification_service: NotificationService`
- Updated constructor and notification call to use the service
The notification uses the user's configured sound and settings, and triggers when a tool requires approval.
* Cleanup script changes for task attempt af6bac2d-a3ba-4c6a-ae35-3a54bd05212f
* Done! The refactoring is complete. Here's a summary:
## Summary
Refactored `NotificationService` to be accessed via the `ContainerService` trait, making it cleaner:
**Changes made:**
1. **`crates/services/src/services/container.rs`**
- Added `fn notification_service(&self) -> &NotificationService` to the trait
- Simplified `finalize_task` signature to `(&self, share_publisher, ctx)` - removed the notification_service parameter
- `finalize_task` now calls `self.notification_service().notify_execution_halted(ctx)`
2. **`crates/local-deployment/src/container.rs`**
- Implemented `fn notification_service(&self) -> &NotificationService` returning `&self.notification_service`
- Updated all 4 `finalize_task` call sites to use the simplified signature
The notification service is now a first-class member of the `ContainerService` trait, following the same pattern as `db()`, `git()`, and `share_publisher()`.
* Cleanup script changes for task attempt af6bac2d-a3ba-4c6a-ae35-3a54bd05212f
* Done! Here's a summary of all the changes:
## Final Summary
**Feature implemented:** Play notification sound when approval is needed.
**Files modified:**
1. **`crates/services/src/services/notification.rs`**
- Added `config: Arc<RwLock<Config>>` field and `new()` constructor
- Removed `notify_execution_halted` method (moved application logic out)
- Kept only generic `notify(title, message)` method
2. **`crates/services/src/services/container.rs`**
- Added `fn notification_service(&self) -> &NotificationService` to trait
- Moved notification logic into `finalize_task`:
- Skip notification if process was killed
- Build title/message based on execution status
- Call `self.notification_service().notify(...)`
3. **`crates/local-deployment/src/container.rs`**
- Added `notification_service: NotificationService` field
- Implemented `notification_service()` accessor
- Simplified `finalize_task` calls (removed notification_service parameter)
- Pass `notification_service.clone()` to `ExecutorApprovalBridge`
4. **`crates/services/src/services/approvals/executor_approvals.rs`**
- Added `notification_service: NotificationService` field
- Calls `self.notification_service.notify("Approval Needed", ...)` when approval is requested
The `NotificationService` is now a clean, reusable service that only handles notifications without any application-specific logic.
* Cleanup script changes for task attempt af6bac2d-a3ba-4c6a-ae35-3a54bd05212f
* All checks pass. Let me summarize what was implemented:
## Summary
I've successfully implemented the draft PR feature. Here's what was changed:
### Backend Changes
1. **`crates/server/src/routes/task_attempts.rs`** (lines 70-76, 724-731):
- Added `draft: Option<bool>` field to `CreateGitHubPrRequest` struct
- Pass the draft field to the `CreatePrRequest` when creating PRs
2. **`crates/services/src/services/github.rs`** (lines 146-153):
- Added `draft: Option<bool>` field to `CreatePrRequest` struct
3. **`crates/services/src/services/github/cli.rs`** (lines 158-160):
- Added logic to pass `--draft` flag to `gh pr create` when draft is true
### Frontend Changes
4. **`frontend/src/components/dialogs/tasks/CreatePRDialog.tsx`**:
- Added `Checkbox` import
- Added `isDraft` state (default: false)
- Added checkbox UI with label from translations
- Pass `draft: isDraft` in the API call
- Reset `isDraft` on success and cancel
### Type Generation
5. **`shared/types.ts`** (auto-generated):
- `CreateGitHubPrRequest` now includes `draft: boolean | null`
### Translations
6. Added `"draftLabel"` translation key to all locale files:
- `frontend/src/i18n/locales/en/tasks.json`: "Create as draft"
- `frontend/src/i18n/locales/es/tasks.json`: "Crear como borrador"
- `frontend/src/i18n/locales/ja/tasks.json`: "下書きとして作成"
- `frontend/src/i18n/locales/ko/tasks.json`: "초안으로 만들기"
- `frontend/src/i18n/locales/zh-Hans/tasks.json`: "创建为草稿"
* Done. I've updated the checkbox to use `h-5 w-5` (20px) and added `text-sm` to the label for consistent sizing.
* The implementation is complete. Here's a summary of all the changes made:
## Summary
### Files Created
- `crates/db/migrations/20251206000000_add_parallel_setup_script_to_projects.sql` - Database migration
### Files Modified
**Backend (Rust):**
- `crates/db/src/models/project.rs` - Added `parallel_setup_script: bool` field to `Project`, `Option<bool>` to `CreateProject`/`UpdateProject`, updated all SQL queries
- `crates/services/src/services/container.rs` - Modified `start_attempt()` to support parallel execution when `parallel_setup_script` is true
- `crates/server/src/routes/projects.rs` - Updated create/update handlers to include new field
- `crates/deployment/src/lib.rs` - Added field to auto-created projects
**Frontend (TypeScript/React):**
- `frontend/src/pages/settings/ProjectSettings.tsx` - Added checkbox UI for parallel setup script setting
- `frontend/src/components/dialogs/projects/ProjectFormDialog.tsx` - Added field to create data
- `frontend/src/components/tasks/TaskDetails/preview/NoServerContent.tsx` - Added field to update data
**i18n:**
- `frontend/src/i18n/locales/en/settings.json` - Added translation strings
- `frontend/src/i18n/locales/es/settings.json` - Added Spanish translations
- `frontend/src/i18n/locales/ja/settings.json` - Added Japanese translations
- `frontend/src/i18n/locales/ko/settings.json` - Added Korean translations
**SQLx Cache:**
- `crates/db/.sqlx/` - Updated query cache files
### Behavior
- When `parallel_setup_script` is `false` (default): Sequential execution (setup → coding agent → cleanup)
- When `parallel_setup_script` is `true`: Setup script and coding agent start simultaneously, setup script failure does not stop the coding agent
* update useConversationHistory to display multiple running conversation threads at once
* The bug fix is complete. Here's a summary of the changes:
## Bug Fix Summary
**Problem:** When running in parallel mode, if the setup script finishes before the coding agent, the task incorrectly moves to "InReview" status while the coding agent is still running.
**Root Cause:** The `should_finalize()` method returned `true` when `next_action.is_none()`, which is the case for setup scripts in parallel mode. This caused premature task finalization.
**Solution:** Modified `should_finalize()` to check if there are other running non-DevServer processes for the same task attempt before finalizing.
### Files Modified
1. **`crates/db/src/models/execution_process.rs`**
- Added `has_running_non_dev_server_processes_excluding()` method that accepts an optional `exclude_id` parameter
- Refactored existing `has_running_non_dev_server_processes()` to delegate to the new method
2. **`crates/services/src/services/container.rs`**
- Changed `should_finalize()` from sync to async
- Added check for other running processes before allowing finalization
3. **`crates/local-deployment/src/container.rs`**
- Updated call site to use `.await` on the now-async `should_finalize()`
* The bug fix is complete. Here's a summary of the changes:
**Fixed files:**
1. **`crates/services/src/services/container.rs`** - Simplified `should_finalize()`:
- Changed from `async fn` back to `fn` (non-async)
- Removed the complex database check for other running processes
- Added a simple check: if the run_reason is `SetupScript` AND `next_action.is_none()` (parallel mode), return `false` (don't finalize)
2. **`crates/local-deployment/src/container.rs`** - Removed `.await` from the `should_finalize()` call
3. **`crates/db/src/models/execution_process.rs`** - Cleaned up by removing the unused `has_running_non_dev_server_processes_excluding()` function and simplifying `has_running_non_dev_server_processes()` back to its original form
**How the fix works:**
- In **parallel mode**: Setup scripts have `next_action: None`, so the new check catches this case and prevents finalization
- In **sequential mode**: Setup scripts have `next_action: Some(coding_agent)`, so they pass this check but won't finalize anyway because `next_action.is_none()` returns `false`
* The implementation is complete. Here's a summary of what was done:
Successfully added environment variable configuration support to executor profiles. Users can now configure env vars like this:
```json
{
"CLAUDE_CODE": {
"DEFAULT": {
"CLAUDE_CODE": {
"env": {
"ANTHROPIC_AUTH_TOKEN": "...",
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
"API_TIMEOUT_MS": "3000000",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-4.6"
}
}
}
}
}
```
1. **`crates/executors/src/command.rs`**:
- Added `env: Option<HashMap<String, String>>` to `CmdOverrides` struct
- Added `apply_env_vars()` helper function
2. **Updated all executors to apply env vars**:
- `claude.rs` - `spawn_internal()`
- `codex.rs` - `spawn()`
- `amp.rs` - `spawn()` and `spawn_follow_up()`
- `droid.rs` - module-level `spawn()` function
- `copilot.rs` - both spawn methods
- `cursor.rs` - both spawn methods
- `opencode.rs` - both spawn methods
- `acp/harness.rs` - `spawn_with_command()` and `spawn_follow_up_with_command()` (used by Gemini/Qwen)
3. **Type Generation**: All JSON schemas and TypeScript types now include the `env` field
This allows users to set environment variables for all supported coding agents (Claude Code, Codex, Gemini, Amp, Droid, Copilot, Cursor, OpenCode, Qwen) through profile configuration, eliminating the need for external tools like claude-code-router.
* The implementation is complete. Here's a summary of what was done:
## Summary
### Backend Changes
- Added `env: Option<HashMap<String, String>>` field to `CmdOverrides` struct in `crates/executors/src/command.rs`
- Created `apply_env_vars()` helper function to inject env vars into `tokio::process::Command`
- Updated all 9 executors to apply env vars during spawn:
- claude.rs, codex.rs, amp.rs, droid.rs, copilot.rs, cursor.rs, opencode.rs
- gemini.rs and qwen.rs (via ACP harness)
- Modified ACP harness signature to accept `Option<&CmdOverrides>`
### Frontend Changes
- Created `KeyValueField.tsx` - custom RJSF field for editing key-value pairs
- Registered the field in `theme.ts`
- Added `uiSchema` to `ExecutorConfigForm.tsx` to use the custom field for `env`
### Generated Files
- `shared/types.ts` - TypeScript types updated with `env` field
- `shared/schemas/*.json` - All 9 executor schemas include `env` property
The environment variables UI will now appear in Settings > Agent Settings as a key-value editor with "Environment Variables" label and description. Users can add/remove/edit env vars that will be passed to the CLI execution environment.
* cleanup env structs
* fix form
* fmt
* remove mise.toml
* fmt
* Seprate config form per selected variant
---------
Co-authored-by: Louis Knight-Webb <louis@bloop.ai>
Co-authored-by: Solomon <abcpro11051@disroot.org>
* The implementation is complete. Here's a summary of what was added:
## Summary
I've implemented the endpoint to fetch all GitHub PR comments for a task attempt. The new endpoint is:
**`GET /api/task-attempts/{id}/pr/comments`**
### Files Modified
1. **`crates/services/src/services/github/cli.rs`**
- Added `PrCommentAuthor` and `PrComment` types
- Added `get_pr_comments()` method to `GhCli` that runs `gh pr view N --repo owner/repo --json comments`
- Added `parse_pr_comments()` helper to parse the JSON response
2. **`crates/services/src/services/github.rs`**
- Exported `PrComment` and `PrCommentAuthor` types
- Added async `get_pr_comments()` method with retry logic (exponential backoff)
3. **`crates/server/src/routes/task_attempts.rs`**
- Added `PrCommentsResponse` struct
- Added `GetPrCommentsError` enum with variants: `NoPrAttached`, `GithubCliNotInstalled`, `GithubCliNotLoggedIn`
- Added `get_pr_comments()` handler function
- Registered the route at `/pr/comments`
4. **`crates/server/src/bin/generate_types.rs`**
- Registered all new types for TypeScript generation
### Generated TypeScript Types
```typescript
type PrCommentsResponse = { comments: Array<PrComment> };
type GetPrCommentsError =
| { "type": "no_pr_attached" }
| { "type": "github_cli_not_installed" }
| { "type": "github_cli_not_logged_in" };
type PrComment = {
id: string,
author: PrCommentAuthor,
authorAssociation: string,
body: string,
createdAt: string,
url: string
};
type PrCommentAuthor = { login: string };
```
* The enhancement is complete. Here's a summary of the changes:
## Summary
Enhanced the `GET /api/task-attempts/{id}/pr/comments` endpoint to fetch **both** general PR comments AND inline review comments, merged into a unified timeline.
### Response Format
```json
{
"success": true,
"data": {
"comments": [
{
"comment_type": "general",
"id": "IC_kwDOO7s21M7XzqRP",
"author": "stunningpixels",
"author_association": "MEMBER",
"body": "Testing comments",
"created_at": "2025-12-06T16:15:10Z",
"url": "https://github.com/BloopAI/vibe-kanban/pull/1447#issuecomment-..."
},
{
"comment_type": "review",
"id": 2595085092,
"author": "stunningpixels",
"author_association": "MEMBER",
"body": "undo this",
"created_at": "2025-12-06T16:15:18Z",
"url": "https://github.com/BloopAI/vibe-kanban/pull/1447#discussion_r...",
"path": "frontend/src/components/layout/Navbar.tsx",
"line": 23,
"diff_hunk": "@@ -20,7 +20,6 @@ import {...}"
}
]
}
}
```
### TypeScript Types
```typescript
type UnifiedPrComment =
| { comment_type: "general"; id: string; author: string; author_association: string; body: string; created_at: string; url: string; }
| { comment_type: "review"; id: bigint; author: string; author_association: string; body: string; created_at: string; url: string; path: string; line: bigint | null; diff_hunk: string; };
```
* Add GitHub review comments (vibe-kanban b9ab9ab2)
frontend/src/components/tasks/TaskFollowUpSection.tsx
- New button to the right of attachment with github comment icon
- If user clicks, opens dialog
- Dialog will display list of comments, format like this:
```javascript
{
"comments": [
{
"id": "IC_kwDOO7s21M7XAc3c",
"author": {
"login": "LSRCT"
},
"authorAssociation": "MEMBER",
"body": "Hi! I tried to get claude to use the `AskUserQuestion` tool in vibe kanban but did not manage, it does not seem to have access to the tool at all. Could you give me a hint on how to best test this PR?",
"createdAt": "2025-12-03T14:46:49Z",
"includesCreatedEdit": false,
"isMinimized": false,
"minimizedReason": "",
"reactionGroups": [],
"url": "https://github.com/BloopAI/vibe-kanban/pull/1395#issuecomment-3607219676",
"viewerDidAuthor": false
},
{
"id": "IC_kwDOO7s21M7Xc1Pi",
"author": {
"login": "davidrudduck"
},
"authorAssociation": "NONE",
"body": "> Hi! I tried to get claude to use the `AskUserQuestion` tool in vibe kanban but did not manage, it does not seem to have access to the tool at all. Could you give me a hint on how to best test this PR?\r\n\r\nI must have been having a daft night when I submitted this - am fixing this at the moment.",
"createdAt": "2025-12-04T22:57:18Z",
"includesCreatedEdit": false,
"isMinimized": false,
"minimizedReason": "",
"reactionGroups": [],
"url": "https://github.com/BloopAI/vibe-kanban/pull/1395#issuecomment-3614659554",
"viewerDidAuthor": false
}
]
}
```
The user will select a comment, this will then be added as a component to the chat.
The component should be fully serializable/deserializable as markdown <> WYSIWYG, just like we do for images atm.
The backend will be implemented separately so just hardcode a mock response in the frontend for now.
* PR 1449 failed because of i18n regressions (vibe-kanban 723e309c)
Please resolve the 7 hardcoded strings this PR introduces https://github.com/BloopAI/vibe-kanban/pull/1449
* PR 1449 failed because of i18n regressions (vibe-kanban 723e309c)
Please resolve the 7 hardcoded strings this PR introduces https://github.com/BloopAI/vibe-kanban/pull/1449
* I've successfully implemented the two new API endpoints for running setup and cleanup scripts on task attempts. Here's a summary of the changes:
## Summary
### Files Modified
1. **`crates/server/src/routes/task_attempts.rs`**
- Added `RunScriptError` enum type for error handling when no script is configured
- Added `run_setup_script` handler - POST endpoint to run a project's setup script
- Added `run_cleanup_script` handler - POST endpoint to run a project's cleanup script
- Registered both routes: `/run-setup-script` and `/run-cleanup-script`
2. **`crates/server/src/bin/generate_types.rs`**
- Added `RunScriptError` to the list of types to export to TypeScript
3. **`shared/types.ts`** (auto-generated)
- Now includes the `RunScriptError` TypeScript type
### New Endpoints
- **`POST /api/task-attempts/{id}/run-setup-script`** - Runs the project's setup script in the task attempt's worktree
- **`POST /api/task-attempts/{id}/run-cleanup-script`** - Runs the project's cleanup script in the task attempt's worktree
Both endpoints:
- Return `ExecutionProcess` on success with the created execution process
- Return `RunScriptError::NoScriptConfigured` if the project doesn't have the respective script configured
- Track analytics events (`setup_script_executed` / `cleanup_script_executed`)
- Use the existing `ScriptContext::SetupScript` / `ScriptContext::CleanupScript` and `ExecutionProcessRunReason::SetupScript` / `ExecutionProcessRunReason::CleanupScript` patterns
* Done! I've added the running process check to both `run_setup_script` and `run_cleanup_script` endpoints. Here's a summary of the changes:
## Summary
### Files Modified
1. **`crates/db/src/models/execution_process.rs`**
- Added `has_running_non_dev_server_processes` method that checks if any running processes (excluding dev servers) exist for a task attempt
2. **`crates/server/src/routes/task_attempts.rs`**
- Added `ProcessAlreadyRunning` variant to `RunScriptError` enum
- Added check at the start of both `run_setup_script` and `run_cleanup_script` handlers to return an error if non-dev-server processes are already running
3. **`shared/types.ts`** (auto-generated)
- `RunScriptError` now includes both `no_script_configured` and `process_already_running` variants
### Behavior
Both endpoints now:
1. First check if any non-dev-server processes (coding agents, setup/cleanup scripts) are running on the task attempt
2. If running processes exist, return `RunScriptError::ProcessAlreadyRunning`
3. Otherwise proceed with script execution as before
* Cleanup script changes for task attempt cdb9cbd9-a6e7-4936-8e75-6dd837c634f3
* Done! I've implemented the frontend changes for the setup/cleanup script dropdown. Here's a summary:
## Summary of Frontend Changes
### Files Modified
1. **`frontend/src/lib/api.ts`**
- Added `RunScriptError` to imports from shared types
- Added `runSetupScript` and `runCleanupScript` methods to `attemptsApi`
2. **`frontend/src/components/tasks/TaskFollowUpSection.tsx`**
- Added imports for `Terminal` icon, `DropdownMenu`, and `Tooltip` components
- Added `attemptsApi` import
- Updated `useProject()` to also get `project` data
- Added computed values: `hasSetupScript`, `hasCleanupScript`, `hasAnyScript`
- Added handlers: `handleRunSetupScript`, `handleRunCleanupScript`
- Added dropdown button with Terminal icon after the Attach button
- Dropdown only shows if project has at least one script configured
- Menu items are disabled with tooltips when scripts are not configured
- Button is disabled when `isAttemptRunning` is true
3. **`frontend/src/i18n/locales/en/tasks.json`**
- Added translation strings for the dropdown menu items and tooltips
### Behavior
- **Dropdown visibility**: Only shown if project has `setup_script` or `cleanup_script` configured
- **Button disabled state**: When `isAttemptRunning` is true (tooltip explains why)
- **Menu item disabled states**:
- "Run setup script" disabled if no `setup_script` (tooltip explains)
- "Run cleanup script" disabled if no `cleanup_script` (tooltip explains)
- **After clicking**: Script starts executing and `isAttemptRunning` becomes true automatically, preventing further interactions
* Done! I've added translations for all languages:
- **Spanish (es)**:
- "Ejecutar script de configuración" / "Ejecutar script de limpieza"
- Tooltips in Spanish
- **Japanese (ja)**:
- "セットアップスクリプトを実行" / "クリーンアップスクリプトを実行"
- Tooltips in Japanese
- **Korean (ko)**:
- "설정 스크립트 실행" / "정리 스크립트 실행"
- Tooltips in Korean
* Done! I've removed all the fallback strings from the `t()` calls. All 5 translation calls now use just the key:
- `{t('followUp.scriptsDisabledWhileRunning')}`
- `{t('followUp.runSetupScript')}`
- `{t('followUp.noSetupScript')}`
- `{t('followUp.runCleanupScript')}`
- `{t('followUp.noCleanupScript')}`
* Done! Here's a summary of the changes:
1. **`scripts/prepare-db.js`** - Added `--check` flag support that runs `cargo sqlx prepare --check` instead of `cargo sqlx prepare`
2. **`package.json`** - Added new script:
```json
"prepare-db:check": "node scripts/prepare-db.js --check"
```
3. **`.github/workflows/test.yml`** - Added `npm run prepare-db:check` to the Checks step
The check will verify that the `.sqlx/` cached query metadata is up-to-date with the actual SQL queries in the codebase. If a developer modifies a SQL query but forgets to run `npm run prepare-db`, the CI will fail.
* Fix image queries
* Done! Added check mode support to the remote script:
1. **`crates/remote/scripts/prepare-db.sh`** - Added `--check` flag support that runs `cargo sqlx prepare --check` when passed
2. **`package.json`** - Added:
```json
"remote:prepare-db:check": "cd crates/remote && bash scripts/prepare-db.sh --check"
```
Note: I didn't add `remote:prepare-db:check` to CI since it requires PostgreSQL (`initdb`, `pg_ctl`) which may not be available on the CI runner. The local SQLite-based `prepare-db:check` is already in CI. Let me know if you'd like to add the remote check to CI as well (would require installing PostgreSQL in the workflow).
* Add remote db check to workflow
* Added a step to install `sqlx-cli` with both SQLite and PostgreSQL features. The Rust cache should help speed up subsequent runs since it caches installed crates.
* Done! All three files updated to use Rust `1.89.0`:
1. `rust-toolchain.toml` - `channel = "1.89.0"`
2. `.github/workflows/test.yml` - `toolchain: 1.89.0`
3. `.github/workflows/pre-release.yml` - `RUST_TOOLCHAIN: 1.89.0`
This should fix the `zerocopy` AVX512 compile error since 1.89.0 has `stdarch_x86_avx512` stabilized.
* Done. Added a step to install PostgreSQL before the Checks step so `npm run remote:prepare-db:check` can run.
* Updated to install `postgresql-16` and add `/usr/lib/postgresql/16/bin` to PATH so `initdb`, `pg_ctl`, and `createdb` are available.
* Added the official PostgreSQL apt repository so we can install PostgreSQL 16.
* Much cleaner. Using the `ikalnytskyi/action-setup-postgres@v7` action which handles the PostgreSQL 16 installation and PATH setup automatically.
* Done. Changes made:
1. **`crates/remote/scripts/prepare-db.sh`**: Now checks if `DATABASE_URL` is set. If so, uses the existing PostgreSQL server. Otherwise creates a temp cluster as before.
2. **`.github/workflows/test.yml`**:
- Added `database: remote` to the PostgreSQL action to create the database
- Added `DATABASE_URL: postgres://postgres@localhost:5432/remote` env var to the Checks step
* Done. Changes made:
1. **`.github/workflows/test.yml`**: Removed PostgreSQL setup step and `DATABASE_URL` env var
2. **`crates/remote/scripts/prepare-db.sh`**: Simplified - for `--check` mode, exits early with `SQLX_OFFLINE=true cargo sqlx prepare --check` (no database needed)
* The implementation is complete. Here's a summary of what was done:
I've implemented environment variable injection when launching coding agents. The following environment variables are now injected into the shell when an executor is spawned:
- `VK_PROJECT_NAME` - Name of the project
- `VK_TASK_ID` - UUID of the task
- `VK_ATTEMPT_ID` - UUID of the task attempt
- `VK_ATTEMPT_BRANCH` - Branch name for the attempt (e.g., `vk/branch-name`)
1. **Created `crates/executors/src/env.rs`** - New module containing `ExecutionEnv` struct with:
- `HashMap<String, String>` to store env vars
- `insert()` method to add env vars
- `apply_to_command()` method to apply env vars to a `tokio::process::Command`
2. **Updated `crates/executors/src/actions/mod.rs`** - Modified `Executable` trait to accept `Option<&ExecutionEnv>` parameter
3. **Updated `crates/executors/src/executors/mod.rs`** - Modified `StandardCodingAgentExecutor` trait's `spawn()` and `spawn_follow_up()` to accept `Option<&ExecutionEnv>` parameter
4. **Updated all action implementations**:
- `coding_agent_initial.rs` - forwards env to agent spawn
- `coding_agent_follow_up.rs` - forwards env to agent spawn
- `script.rs` - applies env vars to script commands
5. **Updated all executor implementations** to apply env vars:
- `claude.rs`, `amp.rs`, `gemini.rs`, `codex.rs`, `qwen.rs`, `droid.rs`, `cursor.rs`, `copilot.rs`, `opencode.rs`
- Also updated `acp/harness.rs` which is used by gemini and qwen
6. **Updated `crates/local-deployment/src/container.rs`** - Modified `start_execution_inner()` to:
- Load task and project context from database
- Create `ExecutionEnv` with the four `VK_*` variables
- Pass the env to `executor_action.spawn()`
* Cleanup script changes for task attempt 4dc9b26c-c637-465a-ae71-644c828ea8f7
* The refactoring is complete. I've successfully updated the `env` parameter from `Option<&ExecutionEnv>` to `&ExecutionEnv` across all relevant files:
**Summary of changes:**
1. **Trait updates:**
- `Executable` trait in `crates/executors/src/actions/mod.rs`
- `StandardCodingAgentExecutor` trait in `crates/executors/src/executors/mod.rs`
2. **Action implementations:**
- `coding_agent_initial.rs`
- `coding_agent_follow_up.rs`
- `script.rs`
3. **Executor implementations (all 10 executors):**
- `claude.rs` - spawn, spawn_follow_up, spawn_internal
- `amp.rs` - spawn, spawn_follow_up
- `gemini.rs` - spawn, spawn_follow_up
- `codex.rs` - spawn, spawn_follow_up, spawn_inner
- `qwen.rs` - spawn, spawn_follow_up
- `droid.rs` - spawn, spawn_follow_up, spawn_droid helper
- `cursor.rs` - spawn, spawn_follow_up
- `copilot.rs` - spawn, spawn_follow_up
- `opencode.rs` - spawn, spawn_follow_up
- `acp/harness.rs` - spawn_with_command, spawn_follow_up_with_command
4. **Call site:**
- `container.rs` in `start_execution_inner` - changed `Some(&env)` to `&env`
All tests pass (137 tests) and clippy reports no warnings.
* All tests pass. The change is complete.
**Summary**: Added `VK_PROJECT_ID` to the environment variables injected when launching coding agents.
The environment variables now include:
- `VK_PROJECT_NAME` - project name
- `VK_PROJECT_ID` - project UUID (newly added)
- `VK_TASK_ID` - task UUID
- `VK_ATTEMPT_ID` - attempt UUID
- `VK_ATTEMPT_BRANCH` - git branch name for the attempt
* undo ts-rs bindings
* All 147 tests pass. The rebase conflict has been resolved successfully.
**Summary:**
- Resolved the rebase conflict in `crates/local-deployment/src/container.rs`
- The conflict was in the imports section where:
- `origin/main` added `InterruptSender` to the executors import
- Our branch added `env::ExecutionEnv` import
- Resolution: Combined both changes to keep `ExecutionEnv` import AND `InterruptSender`
- All tests pass (147 tests)
The branch `vk/4dc9-inject-env-vars` is now rebased onto `origin/main` with the complete environment variable injection feature, including:
- `VK_PROJECT_NAME`
- `VK_PROJECT_ID`
- `VK_TASK_ID`
- `VK_ATTEMPT_ID`
- `VK_ATTEMPT_BRANCH`
* remove bindings (again)
* Simplify glob file search
Switch to globwalk
* Cleanup
* Fix single file continue, add timeout to copy files
* Remove error in copy file dropdown when no match found
* Remove error message for file search text are, remove dead code
* Move copy logic to copy.rs
* I have bumped the `amp` version to `0.0.1764705684-g95eb77` in [crates/executors/src/executors/amp.rs](file:///private/var/folders/fr/0c4ky3392mb4yz5knw_wjdd00000gn/T/vibe-kanban/worktrees/5070-bump-amp/crates/executors/src/executors/amp.rs).
I verified the changes by running `cargo check --workspace`, which passed successfully.
* I have updated the `amp` version to `0.0.1764777697-g907e30` in [crates/executors/src/executors/amp.rs](file:///private/var/folders/fr/0c4ky3392mb4yz5knw_wjdd00000gn/T/vibe-kanban/worktrees/5070-bump-amp/crates/executors/src/executors/amp.rs).
I verified the changes by running `cargo check --workspace` (after resolving a transient `libsqlite3-sys` build issue).
```
M crates/remote/scripts/prepare-db.sh
```
The changes in `crates/remote/scripts/prepare-db.sh` are pre-existing in this worktree, not something I introduced. My only change was to `crates/remote/src/db/organizations.rs`.
Should I revert that file to clean up the branch, or is that a separate change you were working on?
* Disable OAuth account deduplication by email
We intend to add explicit OAuth account linking in the future to replace this issue.
* remove unused function find_user_by_email
* WIP - Migrate task sharing to ElectricSQL + Tanstack DB
* WIP auth proxy
* Simplify electric host
* Electric token
Only set in cloud. Acts like a DB password.
* Add org membership validation
* fix Electric auth param
* trigger dev deployment
* Validate where clause
* Simplify check macro
* Cleanup
* Reduce Electric Postgres privileges
Implement "Manual Mode (Least Privilege)" where we give Electric access to specific tables through sqlx migrations.
https://electric-sql.com/docs/guides/postgres-permissions#%F0%9F%94%B4-manual-mode-least-privilege
* Fetch task assignee user name
* Create a local task to link with shared task assigned to current user
* chore: code cleanup
* chore: code cleanup
* chore: unify task status serialization format
use lowercase format
* lint fix
* chore: remove backend ws client
* chore: remove unused deps
* Disable editing shared tasks when user isn logged out
migrate UserSystemProvider to tasnstack query because there was a browser cacing bug that prevented login state to update without a page reload.
* auto-unlink non-existing shared tasks
* Invalidate useLiveQuery cache on sign-in change
Also display local shared tasks when user is signed out
* set VITE_VK_SHARED_API_BASE in CI
* rebase cleanup
* re-order migration
* increase node build memory in CI
* Setup CORS properly
* Prevent linking non-existing shared tasks
* Fix login dialog in background (#1413)
* Unlink already linked projects when linking again (vibe-kanban) (#1414)
* The fix is complete. Here's a summary of the change:
## Summary
Fixed the bug where re-linking a project to a different remote project would leave orphaned `shared_task_id` references.
**File modified:** `crates/server/src/routes/projects.rs:167-208`
**Change:** The `apply_remote_project_link` function now:
1. Fetches the existing project to check if it's already linked
2. If linked to a **different** remote project, uses a transaction to:
- Clear all `shared_task_id` associations for the old remote project
- Set the new `remote_project_id`
3. If no existing link, sets the new link directly
4. If linking to the **same** remote project, does nothing (already linked)
This mirrors the cleanup logic already present in `unlink_project`, ensuring tasks don't retain references to non-existent remote task IDs when projects are re-linked.
* You're right, let me think more carefully about the transaction.
Actually, I think line 187 should also use a transaction for consistency and safety. Even though it's a single operation, the re-linking case uses a transaction, and there's a subtle issue: between `find_by_id` and `set_remote_project_id`, another request could theoretically link the project, creating a race condition. Using a transaction would provide row-level locking.
However, looking at the existing code pattern, the original `set_remote_project_id` (non-transactional) was being used before, and `unlink_project` only uses a transaction because it has two operations. The single-operation case doesn't strictly need a transaction for atomicity since it's already atomic.
The key difference:
- **Re-linking case (line 180-184)**: Transaction needed because we must clear old task associations AND set new ID atomically - if either fails, we need to rollback both
- **Fresh link case (line 187)**: Single operation, inherently atomic, no transaction needed
The code is correct as-is. Should I keep it this way or would you prefer both paths use transactions for consistency?
* Done. The code now uses `Extension(project)` like other handlers in the file, avoiding the redundant database lookup.
* Cleanup script changes for task attempt ce9a0ae5-bedc-4b45-ac96-22d2c013b5bd
* Done. Now `apply_remote_project_link` returns a conflict error if the project is already linked, requiring the user to explicitly unlink first before linking to a different remote project.
* Both pass. Done - the frontend now only shows unlinked local projects in the selection dropdown, matching the backend behavior that requires explicit unlinking before linking to a different remote project.
* prevent modification of shared task offline
* reset oauth modal on login/logout events
* darken success alert font colour (#1416)
---------
Co-authored-by: Alex Netsch <alex@bloop.ai>
Co-authored-by: Louis Knight-Webb <louis@bloop.ai>
Co-authored-by: Gabriel Gordon-Hall <gabriel@bloop.ai>
* fix: No conversation found with session ID issue
Load session id after session is initialized.
* fmt
* claude: ignore session from message fragments
* fix tests
* Replace follow up section with WYSIWYG (vibe-kanban 55b58b24)
frontend/src/components/tasks/TaskFollowUpSection.tsx
frontend/src/components/ui/wysiwyg.tsx
* Delete all usage of image chip component (vibe-kanban 5c90eac1)
frontend/src/components/ui/wysiwyg/image-chip-markdown.ts
frontend/src/components/ui/wysiwyg/image-chip-node.tsx
* Trigger file / tag picker from WYSIWYG (vibe-kanban 3e73cf53)
LexicalTypeaheadMenuPlugin
frontend/src/components/ui/wysiwyg.tsx
frontend/src/components/ui/file-search-textarea.tsx (old)
* Editor state should be saved as JSON (vibe-kanban 4f9eec74)
Instead of saving markdown, we should save JSON eg `editorState.toJSON();`.
This will enable us to properly serialize custom Elements in the future.
frontend/src/components/ui/wysiwyg.tsx
frontend/src/components/tasks/follow-up/FollowUpEditorCard.tsx
* In WYSIWYG, the search dialog can exceed screen (vibe-kanban 25337029)
When searching for tags/files. Sometimes the dialog is cut off the bottom of the screen.
frontend/src/components/ui/wysiwyg.tsx
* Use WYSIWYG for tasks (vibe-kanban 5485d481)
Currently used for follow ups, we should also use for task
frontend/src/components/tasks/follow-up/FollowUpEditorCard.tsx
frontend/src/components/dialogs/tasks/TaskFormDialog.tsx
frontend/src/components/ui/wysiwyg.tsx
* Keyboard shortcuts when typing in WYSIWYG (vibe-kanban 04bd70bc)
We used to have a callback for:
- CMD+Enter
- Shift+CMD+Enter
In create task dialog:
- CMD+Enter = create and start
- Shift+CMD+Enter = create without start
In follow up:
- CMD+Enter = Follow up
- Shift+CMD+Enter = nothing
frontend/src/components/tasks/follow-up/FollowUpEditorCard.tsx
frontend/src/components/ui/wysiwyg.tsx
frontend/src/components/dialogs/tasks/TaskFormDialog.tsx
Ideally we can use the relevant Lexical plugin and callbacks, cleaning up the old `@/keyboard` hooks which no longer work.
* Trigger file / tag picker from WYSIWYG (vibe-kanban 3e73cf53)
LexicalTypeaheadMenuPlugin
frontend/src/components/ui/wysiwyg.tsx
frontend/src/components/ui/file-search-textarea.tsx (old)
* Use WYSIWYG for tasks (vibe-kanban 5485d481)
Currently used for follow ups, we should also use for task
frontend/src/components/tasks/follow-up/FollowUpEditorCard.tsx
frontend/src/components/dialogs/tasks/TaskFormDialog.tsx
frontend/src/components/ui/wysiwyg.tsx
* Introduce new user-message table and struct (vibe-kanban 09116513)
{
ID,
message_json: Value,
message_md: String
}
We'll also need some endpoints to CRUD them.
crates/db
crates/server
* Stream individual scratch (vibe-kanban 321b50a1)
crates/server/src/routes/scratch.rs
It should be possible to listen for updates made to a single scratch
* Refactor useScratch (vibe-kanban 51ea2317)
To consolidate the API stuff into frontend/src/lib/api.ts
* Update scratch API (vibe-kanban 878f40c5)
Primary key should come from: ID and scratch type combination
The frontend will provide both.
Scratch IDs should not be generated on the backend.
* Remove all usage of hook from follow up (vibe-kanban 2d691095)
Use of hooks that reside in frontend/src/hooks/follow-up/* should be removed, except for frontend/src/hooks/follow-up/useFollowUpSend.ts
From: frontend/src/components/tasks/TaskFollowUpSection.tsx
* Task follow up should use scratch (vibe-kanban d37d3b18)
The current task attempt ID should be used to save the content of the follow up box as scratch.
frontend/src/components/tasks/TaskFollowUpSection.tsx
* Use just markdown serialization for scratch (vibe-kanban 42f5507f)
frontend/src/hooks/useScratch.ts
crates/server/src/routes/scratch.rs
crates/db/src/models/scratch.rs
We are currently storing JSON + MD, however we should now store just MD and import/export the markdown into lexical.
* Consolidate MarkdownRenderer and WYSIWYG (vibe-kanban f61a7d40)
Currently we have an old implementation of markdown rendering in frontend/src/components/ui/markdown-renderer.tsx
But we have recently introduced the new WYSIWYG editor frontend/src/components/ui/wysiwyg.tsx
wysiwyg takes JSON as input, not raw markdown.
Ideally we could just use a single component and have a read only mode, removing Markdown Renderer and its dependencies and custom styling.
* WYSIWYG images (vibe-kanban 8cc3c0e7)
Create a Lexical plugin for images, with markdown import/export support.
Visually, images should be displayed as a small thumbnail with the path truncated.
Export/import should support standard markdown image format.
* Get image metadata endpoint (vibe-kanban 2c0dfbff)
Task attempt endpoint to get info, given the relative URL of an image.
We will also need an image that acts as a proxy to the file.
Info to return:
- Whether file exists
- Size of image
- Format
- File name
- Path
- URL to get image (the proxy URL)
The images are stored in the `.vibe-images` folder, relative to the task attempt container.
crates/server/src/routes/task_attempts.rs
* Inject relative path not absolute to image (vibe-kanban 007d589b)
Currently when we upload an image, it adds markdown with the full relative path of the image, eg:
/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban-dev/worktrees/2702-testing-images/.vibe-images/b01e6b02-dbd0-464c-aa9f-a42a89f6d67b.png
However, we should change this to be the path relative to the worktree eg .vibe-images/b01e6b02-dbd0-464c-aa9f-a42a89f6d67b.png
* Improve image in WYSIWYG (vibe-kanban 53de9071)
frontend/src/components/ui/wysiwyg/nodes/image-node.tsx
Check if the image comes from `./vibe-images/...`, if so:
Use the API endpoints to get and display metadata.
Use the image proxy to display the thumbnail image.
Do not render non `.vibe-images` images, instead just show the path and show a question icon as a thumbnail.
* rebase fixes
* Add Lexical toolbar (vibe-kanban b8904ad9)
frontend/src/components/ui/wysiwyg.tsx
* Clicking image once should open dialog (vibe-kanban aab2e6f4)
frontend/src/components/ui/wysiwyg/nodes/image-node.tsx
* Style quotes better (vibe-kanban 54718e76)
frontend/src/components/ui/wysiwyg.tsx
* Auto detect multi-line code blocks (vibe-kanban ce33792d)
Currently when I type triple backticks it doesn't create a multi-line code block
frontend/src/components/ui/wysiwyg.tsx
* Update how image upload works on the backend (vibe-kanban 62d97322)
I am only referring to the image upload for sending a follow up message.
Currently we:
- upload an image
- when a follow up is made, send file IDs
- copy the image into container based on those file IDs
We should tweak this so that:
- upload an image
- immediately the image is copied into container
- the image file location is added to the markdown of the follow up message (on the frontend)
- when user makes follow up, the image is already in the container
crates/server/src/routes/images.rs
crates/server/src/routes/task_attempts/images.rs
* Use @lexical/code to render code (vibe-kanban 60605a2c)
frontend/src/components/ui/wysiwyg.tsx
* Save variant in scratch (vibe-kanban 06e1e255)
frontend/src/components/tasks/TaskFollowUpSection.tsx
* prepare db
* Solve follow up loading when empty (vibe-kanban 1991bf3d)
frontend/src/components/tasks/TaskFollowUpSection.tsx
Currently the loader shows when the scratch data is loading, but also when there is no scratch data - which means the user can never see the follow up inputs
* descriptive scratch error
* Triple backtick WYSIWYG not working properly (vibe-kanban 30b0114e)
When I paste in a multi-line code block, eg
```js
var x = 100;
```
It doesn't add a multi-line code block properly, instead it created two multi-line code blocks above and below the code.
frontend/src/components/ui/wysiwyg.tsx
* Safe scratch fail (vibe-kanban c3f99b37)
It's possible to get an error like:
scratch WS closed: Failed to get scratch item: invalid type: string "\\`\\`\\`js\n\nvar x = 100;\n\n\\`\\`\\` \n\n\n", expected struct DraftFollowUpData at line 1 column 49
In this situation the websocket should act in the same way when no scratch exists yet.
* Remove drafts (vibe-kanban 0af2e9aa)
crates/services/src/services/drafts.rs
crates/db/src/models/draft.rs
* Cleanup scratch (vibe-kanban 0baf9b69)
Remove:
- frontend/src/pages/TestScratch.tsx
- frontend/src/components/ScratchEditor.tsx
* Improve styling of WYSIWYG + attachment (vibe-kanban 042a18da)
frontend/src/components/ui/wysiwyg.tsx
The placeholder can overlap the attachment icon
* Introduce queued message service (vibe-kanban 442164ae)
- New service (crates/services/src/services/...) that holds an in memory store
- When the final executor_action finishes, if another follow up prompt (scratch ID) is queued then we can automatically begin executing it (crates/local-deployment/src/container.rs after finalize)
- New endpoint required to modify the queue for a task attempt.
- Scratch should be wiped after the execution process is created
- Scratch can't be edited while queued
- Add button to TaskFollowUpSection to make current scratch queued, or cancel queued item
* prepare db
* Follow up box does not reset after sending message (vibe-kanban c032bc21)
- Type follow up
- Press send
- Expect follow up to be reset, but it is not
frontend/src/components/tasks/TaskFollowUpSection.tsx
* bg
* Fix i18n (vibe-kanban a7ee5604)
i18next::translator: missingKey en-GB tasks followUp.queue Queue
* Reduce re-renders (vibe-kanban 86ec1b47)
frontend/src/components/ui/wysiwyg.tsx
frontend/src/components/tasks/TaskFollowUpSection.tsx
* Speed up button transitions (vibe-kanban be499249)
It takes 0.5-1s for the send button to go from no opacity to full opacity after I start typing
frontend/src/components/tasks/TaskFollowUpSection.tsx
* add icon to variant selection (vibe-kanban 92fca0e6)
frontend/src/components/tasks/TaskFollowUpSection.tsx
Dropdown should have settings-2
* Queued message functionality (vibe-kanban 21c7a725)
Say I have two messages to send:
- I send first
- I queue the second
- I now see "message queued" and the follow up editable text contains the second
- First finishes, second starts, no tasks are queued
- I still see "message queued" box but the follow up editable text gets wiped
frontend/src/components/tasks/TaskFollowUpSection.tsx
* variant width adjust
* Move the attach button (vibe-kanban b7f89e6e)
Attach button should be to the left of of the send button
frontend/src/components/ui/wysiwyg.tsx
frontend/src/components/tasks/TaskFollowUpSection.tsx
* Cleanup WYSIWYG (vibe-kanban 62997d6c)
Props, and upstream logic:
- make placeholder optional:
- remove defaultValue: this seems redundant as value is always controlled, there may also be related cleanups for uncontrolled mode
- remove onFocusChange: toggling states is unnecessary here
- remove enableCopyButton: this is always enabled when the editor is disabled
frontend/src/components/ui/wysiwyg.tsx
* cleanup scratch types
* further scratch cleanup
* Tweak queue (vibe-kanban 642aa7be)
If a task is stopped or fails, the next queued task runs, however this is not the desired behaviour. Instead the queued task should be removed from the queue
* Can't see attach button and queue at the same time (vibe-kanban 75ca5428)
frontend/src/components/tasks/TaskFollowUpSection.tsx
* move follow up hooks
* WYSIWYG code blocks should scroll horizontally (vibe-kanban 6c5dbc99)
frontend/src/components/ui/wysiwyg.tsx
* Refactor useDefaultVariant (vibe-kanban 10ec12ec)
I think we could change this so that it accepts a default variant and then returns what variant is currently selected, based on the user's preferences and if they select one from the dropdown
* Can't retry a task (vibe-kanban dfde6ad8)
It seems to retry functionality was removed fromfrontend/src/components/NormalizedConversation/UserMessage.tsx
* If execution startup is slow, scratch is not reset (vibe-kanban 6e721b8e)
frontend/src/components/tasks/TaskFollowUpSection.tsx
If you write out a follow up and then hit send, if you then navigate away from the page quickly the scratch will still be present when you visit the page, when the expected behaviour is that the previous text would be cleared
* Code highlighting for inline code block (vibe-kanban 956f1d5c)
Currently works for multi-line, can we get it working for multi-line
frontend/src/components/ui/wysiwyg.tsx
* Delete FileSearchTextArea (vibe-kanban 01107879)
Replace with frontend/src/components/ui/wysiwyg.tsx
not frontend/src/components/ui/file-search-textarea.tsx
* Tweak styles in task dialog (vibe-kanban 8dfe95a9)
frontend/src/components/dialogs/tasks/TaskFormDialog.tsx
- Placeholder for WYSIWYG too small, just use default
- Make title same size as WYSIWYG H1
* Refactor retry to use variant hook (vibe-kanban 69c969c9)
frontend/src/hooks/useVariant.ts
frontend/src/components/NormalizedConversation/RetryEditorInline.tsx
frontend/src/contexts/RetryUiContext.tsx
Removing all existing logic related to variant picking
* Refactor approval message styles (vibe-kanban b9a905e1)
Refactor the WYSIWYG implementation in thefrontend/src/components/NormalizedConversation/PendingApprovalEntry.tsx so the styles align with usage infrontend/src/components/tasks/TaskFollowUpSection.tsx
* Fix follow up box font (vibe-kanban 4fa9cd39)
When I start typing, it's a really small font for some reason
frontend/src/components/tasks/TaskFollowUpSection.tsx
* Remove double border for plan approval (vibe-kanban 3f12c591)
frontend/src/components/NormalizedConversation/PendingApprovalEntry.tsx
- Also multi-line code block colour is broken when looking at plans (but not single line strangely...)
* Retry Editor shouldn't call API directly (vibe-kanban 3df9cde5)
Should use hooks frontend/src/components/NormalizedConversation/RetryEditorInline.tsx
* Image metadata for task creation (vibe-kanban 8dd18a28)
We have an endpoint for image metadata in task attempt, but not for task
crates/server/src/routes/images.rs
This means we can't currently render the image (and metadata) in the WYSIWYG editorfrontend/src/components/dialogs/tasks/TaskFormDialog.tsx
* Add file upload to retry (vibe-kanban 8dffeed2)
frontend/src/components/NormalizedConversation/RetryEditorInline.tsx
Similar to:
frontend/src/components/tasks/TaskFollowUpSection.tsx
Infact we should reuse the same component as much as possible
* Remove the client side scratch deletion (vibe-kanban c6b0a613)
frontend/src/components/tasks/TaskFollowUpSection.tsx
This happens now on backend.
Also on backend when queued task is triggered we should also wipe the scratch.
* Queued task style (vibe-kanban 0c9bc110)
frontend/src/components/tasks/TaskFollowUpSection.tsx
When a message is queued it repeats the message under "will execute when current run finishes", however the message is visible anyway in the message box so we can remove that
* WYSIWYG base font size decrease
* Queueing a message change (vibe-kanban 30ee2d4d)
Currently when we queue a message I can see in the logs: Failed to save follow-up draft ApiError: Cannot edit scratch while a message is queued
I think this is because the following is happening:
- User types
- Clicks queue
- Debounce tries to save message
- Can't save message because of queue
1. **`worktree_manager.rs:112`**: Changed "Worktree already properly set up at path" from `debug!` to `trace!`
2. **`path.rs:9`**: Changed "Making path relative" from `tracing::debug!` to `tracing::trace!`
3. **`path.rs:21`**: Changed "Successfully made relative" from `tracing::debug!` to `tracing::trace!` (this is the successful outcome of the path relative operation, also routine)
These are the routine activity logs that fire frequently during normal operation. The other debug logs in these files are either on error/fallback paths or log less frequent events that are more useful for debugging.
OAuth tokens are revoked when the user revoke access to the OAuth app from the provider settings.
Some OAuth providers also revoke OAuth tokens when the user changes password.
* feat: Add setting to use Claude subscription when API key is detected
This commit adds a new optional setting `use_claude_subscription` to the ClaudeCode
executor configuration. When enabled, this setting removes the ANTHROPIC_API_KEY
environment variable before spawning the Claude Code agent, ensuring that users with
Claude Pro/Team subscriptions can opt to use their subscription instead of being
charged API fees.
## Changes
- Added `use_claude_subscription` optional field to the `ClaudeCode` struct
- Implemented logic in `spawn_internal` to conditionally remove `ANTHROPIC_API_KEY`
from the environment when the setting is enabled
- Added tracing log when API key is removed for better debugging
## Implementation Details
- The field is optional (`Option<bool>`) and defaults to `false` when not set,
maintaining backward compatibility
- Uses `#[serde(skip_serializing_if = "Option::is_none")]` to keep JSON clean
- The setting is automatically exposed in the frontend via the JSON Schema
auto-generation from Rust structs
- TypeScript bindings are auto-generated via the `#[derive(TS)]` macro
## Benefits
- Prevents unexpected API charges for users with Claude subscriptions
- Gives users explicit control over authentication method
- Backward compatible - existing configurations continue to work unchanged
- No frontend changes needed - the setting appears automatically in the
ExecutorConfigForm
## Related
- Addresses feature request in discussion #1228
- Design document: https://github.com/potable-anarchy/vibe-kanban-launcher/blob/main/DESIGN_PROPOSAL.md
* cleanups
rename the config parameter to `disable_api_key`.
regenerate type bindings.
* suggest using the setting in the api-key warning
---------
Co-authored-by: Solomon <abcpro11051@disroot.org>