722437617096fc698858526af52db3ee9c9c045e
1242 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bd93f14090 | refactor container and deployments. scope logic appropriately and remove unused code. (#1351) | ||
|
|
036dd802d8 |
Force push (vibe-kanban) (#1350)
* Excellent! All tasks completed successfully. Here's a summary of the changes:
I've successfully added typed error handling to the push method following the same pattern as `CreatePrError`. Here's what was implemented:
1. **Created `PushError` enum** in `crates/server/src/routes/task_attempts.rs:608-613`
- Single variant: `ForcePushRequired`
- Uses proper derives for TypeScript generation
2. **Updated push handler signature** in `crates/server/src/routes/task_attempts.rs:596`
- Changed return type to `Result<ResponseJson<ApiResponse<(), PushError>>, ApiError>`
3. **Registered error type** in `crates/server/src/bin/generate_types.rs:140`
- Added `PushError::decl()` to the type declarations
4. **Generated TypeScript type** in `shared/types.ts:301`
- Type: `export type PushError = { "type": "force_push_required" }`
5. **Updated frontend API** in `frontend/src/lib/api.ts`
- Imported `PushError` type
- Changed `push` method to return `Result<void, PushError>`
- Uses `handleApiResponseAsResult` for proper error handling
6. **Updated `usePush` hook** in `frontend/src/hooks/usePush.ts`
- Created custom `PushErrorWithData` class to properly pass error data
- Updated signature to pass `errorData` to `onError` callback
7. **Updated component error handling** in `frontend/src/hooks/useGitOperations.ts:47-52`
- Added handling for `force_push_required` error type
- Displays user-friendly message: "Force push required. The remote branch has diverged."
All checks pass successfully! The implementation is ready for future force push functionality.
Cleanup script changes for task attempt 982f21cc-f0a3-455d-8b30-3a9911c2889f
Excellent! All tasks completed successfully. Here's a summary of the force push implementation:
I've successfully implemented a complete force push feature with user confirmation. Here's what was done:
1. **Updated Git CLI** (`crates/services/src/services/git/cli.rs:318`)
- Added `force: bool` parameter to `push()` method
- Uses `+refs/heads/{branch}` refspec when force is true
2. **Updated Git Service** (`crates/services/src/services/git.rs:1615`)
- Added `force: bool` parameter to `push_to_github()` method
- Passes force flag to Git CLI
3. **Added Force Push Endpoint** (`crates/server/src/routes/task_attempts.rs:608`)
- New handler: `force_push_task_attempt_branch`
- Calls `push_to_github()` with `force: true`
- Regular push endpoint now passes `force: false`
4. **Added Route** (`crates/server/src/routes/task_attempts.rs:1581`)
- Route: `POST /api/task-attempts/:id/push/force`
5. **API Client** (`frontend/src/lib/api.ts:561`)
- Added `forcePush()` method
- Returns `Result<void, PushError>`
6. **Created useForcePush Hook** (`frontend/src/hooks/useForcePush.ts`)
- React Query mutation for force push
- Handles typed errors
- Invalidates branch status on success
7. **Created ForcePushDialog** (`frontend/src/components/dialogs/git/ForcePushDialog.tsx`)
- Destructive variant with warning icon
- Clear warning about overwriting remote changes
- Buttons: "Cancel" and "Force Push"
8. **Integrated Dialog Flow** (`frontend/src/hooks/useGitOperations.ts:58-85`)
- When regular push fails with `force_push_required` error:
- Shows ForcePushDialog to confirm
- If user confirms, executes force push
- Handles errors from force push operation
1. User attempts to push
2. If remote has diverged, backend returns `force_push_required` error
3. Frontend shows confirmation dialog explaining the consequences
4. User can cancel or confirm force push
5. If confirmed, force push is executed
6. Success/error feedback is shown
All checks pass successfully! The feature is ready to use.
Cleanup script changes for task attempt 982f21cc-f0a3-455d-8b30-3a9911c2889f
Perfect! The fix is complete and all checks pass. Here's what was changed:
**Problem:** The `push_task_attempt_branch` endpoint was using the `?` operator which converted `GitServiceError::GitCLI(GitCliError::PushRejected(_))` into a generic `ApiError`, preventing the frontend from receiving the typed `PushError::ForcePushRequired` error.
**Solution:** Updated the endpoint in `crates/server/src/routes/task_attempts.rs:602-613` to use a `match` statement that:
1. Returns success on `Ok(_)`
2. Detects `GitServiceError::GitCLI(GitCliError::PushRejected(_))` and returns the typed error `ApiResponse::error_with_data(PushError::ForcePushRequired)`
3. Returns generic `ApiError::GitService(e)` for other errors
Now when a push is rejected due to non-fast-forward, the backend will return:
```json
{
"success": false,
"error_data": {
"type": "force_push_required"
}
}
```
This will trigger the force push confirmation dialog in the frontend, allowing the user to choose whether to force push or cancel.
Cleanup script changes for task attempt 982f21cc-f0a3-455d-8b30-3a9911c2889f
Perfect! The fix is complete and all checks pass. Here's what was changed:
**Problem:** The ForcePushDialog was not closing after the user clicked "Force Push" or "Cancel" because it only called `modal.resolve()` without calling `modal.hide()`.
**Solution:** Added `modal.hide()` calls to both handlers in `frontend/src/components/dialogs/git/ForcePushDialog.tsx`:
- **Line 24:** Added `modal.hide()` after `modal.resolve('confirmed')` in `handleConfirm`
- **Line 29:** Added `modal.hide()` after `modal.resolve('canceled')` in `handleCancel`
Now the dialog will properly close when the user clicks either button. This follows the correct NiceModal pattern where you need both:
1. `modal.resolve()` - to resolve the promise with a result
2. `modal.hide()` - to actually hide the dialog
The force push feature should now work end-to-end: push rejection → confirmation dialog → force push → dialog closes.
Perfect! All checks pass. Here's what was fixed:
The force push dialog now follows the same pattern as all other async dialogs in the codebase.
**Added:**
- `attemptId` prop (required) to identify which task attempt to force push
- `useForcePush` hook usage internally
- Loading state with `forcePush.isPending`
- Error state displayed in the dialog
- Loader spinner and "Force Pushing..." button text during operation
- Disabled buttons during operation
- Dialog stays open until operation completes
**Behavior:**
- User clicks "Force Push" → button shows spinner and "Force Pushing..."
- On success → dialog closes automatically
- On error → error shown in dialog, stays open, user can retry or cancel
**Changed:**
- Removed the manual force push call after dialog confirmation
- Now passes `attemptId` to the dialog: `ForcePushDialog.show({ attemptId })`
- Dialog handles the entire force push operation internally
1. User attempts push
2. Push rejected with `force_push_required` error
3. Dialog appears with warning
4. User clicks "Force Push"
5. **Button shows spinner and "Force Pushing..."** ← New!
6. **Buttons disabled during operation** ← New!
7. On success: dialog closes
8. On error: error displayed in dialog, user can retry
This matches the pattern used by CreatePRDialog, GhCliSetupDialog, and other async dialogs in the codebase.
* Force push i18n (vibe-kanban 5519a7db)
Run @scripts/check-i18n.sh until it passes. Make sure to check the script and set GITHUB_BASE_REF to vk/607c-add-pre-flight-c
Force push i18n (vibe-kanban 5519a7db)
Run @scripts/check-i18n.sh until it passes. Make sure to check the script and set GITHUB_BASE_REF to vk/607c-add-pre-flight-c
* fix tests
|
||
|
|
1ef162416d |
Add pre-flight check for target branch existence before PR creation (vibe-kanban) (#1341)
* Excellent! I've successfully implemented the pre-flight check for target branch existence before PR creation. Here's what I did: ## Summary I've added a pre-flight check that verifies the target branch exists on the remote before attempting to create a pull request. This provides a clear, early error message instead of failing during the GitHub API call. ### Changes Made 1. **Added `fetch_and_check_branch_exists()` method** in `crates/services/src/services/git.rs:1414-1446`: - Fetches from the remote to update tracking refs - Checks if the target branch exists (both local and remote branches) - Uses best-effort fetching (doesn't fail if fetch fails) - Returns `Ok(true)` if branch exists, `Ok(false)` if not 2. **Added pre-flight check** in `crates/server/src/routes/task_attempts.rs:639-667`: - Placed before pushing the branch to GitHub - Fetches and verifies the target branch exists - Returns a clear error message if the branch doesn't exist - Continues with PR creation even if the check fails (fallback to GitHub API error) - Includes logging for debugging ### Key Features - **Fail-fast approach**: Catches missing target branch before wasting time on the GitHub API call - **Clear error messages**: Users get an actionable error message: "Target branch 'X' does not exist on remote. Please ensure the branch exists before creating a pull request." - **Graceful degradation**: If the fetch/check fails for any reason, the code continues and lets the GitHub API handle the error (existing fallback behavior) - **Works with all git remotes**: Not GitHub-specific, uses git fetch - **Performance trade-off**: Adds 1-3 seconds for the fetch operation, but provides better UX ### Testing All checks passed: - ✅ Rust compilation (cargo clippy) - ✅ TypeScript type generation (npm run generate-types:check) The implementation follows the "Option A - Fetch-then-check" approach from the task description, providing early detection of missing target branches while maintaining backward compatibility with the existing error handling. * Cleanup script changes for task attempt 607cef96-2669-46e6-bee9-fd2d524be0bd * Perfect! All the review comments have been addressed: ## Changes Made 1. **Simplified `fetch_and_check_branch_exists()` in git.rs** - Now uses the existing `Self::find_branch()` helper method instead of manually calling `repo.find_branch()` twice, making the code cleaner and more consistent with the rest of the codebase. 2. **Removed all comments** from both files - The code is now self-explanatory without the verbose comments. 3. **Removed all logging** from task_attempts.rs - No more `tracing::info!`, `tracing::warn!`, or `tracing::error!` calls for the pre-flight check. 4. **Simplified control flow** - Changed from a match statement to a cleaner if-let pattern as suggested by clippy. The implementation is now more concise while maintaining the same functionality: - Fetches from remote and checks if the target branch exists - Returns a clear error if the branch doesn't exist - Silently continues on success or fetch errors (letting GitHub API handle any remaining issues) All compilation checks pass successfully. * Perfect! All checks pass. Let me create a summary of the changes: I've successfully added a typed error for the missing target branch case. Here's what was changed: 1. **Added `TargetBranchNotFound` variant to `GitHubServiceError`** in `crates/services/src/services/github.rs:38-40`: - Takes a `String` parameter for the branch name - Includes a clear error message - Marked with `#[ts(skip)]` since it has a parameter 2. **Updated `is_api_data()` method** in `crates/services/src/services/github.rs:93`: - Added `GitHubServiceError::TargetBranchNotFound(_)` to the match pattern - This ensures the error is properly typed and won't be retried 3. **Updated `create_github_pr()`** in `crates/server/src/routes/task_attempts.rs:643-645`: - Replaced the string error message with `GitHubServiceError::TargetBranchNotFound(target_branch.clone())` - Now uses `ApiResponse::error_with_data()` instead of `ApiResponse::error()`, consistent with other typed errors in the function - **Type-safe error handling**: Frontend can now properly discriminate this error type - **Consistent with existing patterns**: Follows the same pattern as `TokenInvalid`, `InsufficientPermissions`, etc. - **Better API design**: The error is now part of the function's return type signature All compilation and type generation checks pass successfully! * Great! All checks pass. Let me create a summary: I've successfully added frontend error handling for the `target_branch_not_found` error. Here's what was done: 1. **Added translation key** in `frontend/src/i18n/locales/en/tasks.json:345`: - Key: `createPrDialog.errors.targetBranchNotFound` - Message: `"Target branch '{{branch}}' does not exist on remote. Please ensure the branch exists before creating a pull request."` - Uses interpolation to inject the branch name dynamically 2. **Added error handler** in `frontend/src/components/dialogs/tasks/CreatePRDialog.tsx:187-195`: - Checks if `result.error.type === 'target_branch_not_found'` - Extracts the `branch` field from the error object - Displays localized error message with the branch name interpolated - Clears the GH CLI helper UI state When a user tries to create a PR with a non-existent target branch: 1. **Backend pre-flight check** fetches from remote and checks if the target branch exists 2. **If branch doesn't exist**: Returns `CreatePrError::TargetBranchNotFound { branch: "xyz" }` 3. **Frontend receives** typed error with discriminant `type: "target_branch_not_found"` and `branch: "xyz"` 4. **Dialog displays**: "Target branch 'xyz' does not exist on remote. Please ensure the branch exists before creating a pull request." All checks pass (TypeScript compilation, linting, type generation). * Excellent! All checks pass. Here's the summary: I've successfully added the `targetBranchNotFound` translation key to all 3 missing locale files: 1. **Spanish (es)** - `frontend/src/i18n/locales/es/tasks.json:121`: - `"La rama objetivo '{{branch}}' no existe en el remoto. Por favor, asegúrese de que la rama exista antes de crear una solicitud de extracción."` 2. **Japanese (ja)** - `frontend/src/i18n/locales/ja/tasks.json:121`: - `"ターゲットブランチ '{{branch}}' がリモートに存在しません。プルリクエストを作成する前にブランチが存在することを確認してください。"` 3. **Korean (ko)** - `frontend/src/i18n/locales/ko/tasks.json:121`: - `"대상 브랜치 '{{branch}}'이(가) 원격에 존재하지 않습니다. 풀 리퀘스트를 생성하기 전에 브랜치가 존재하는지 확인하세요."` All translations follow the same pattern with the `{{branch}}` interpolation parameter and maintain consistency with the existing error messages in each locale. All checks pass (TypeScript compilation, frontend and backend checks)! Fix i18n * Perfect! All checks pass. Here's the complete summary: ## Summary I've successfully fixed the branch name format handling issue in `check_remote_branch_exists()`. ### The Problem The method only tried the exact branch name provided (e.g., "main"), but git2's `find_branch()` with `BranchType::Remote` requires the full remote branch name (e.g., "origin/main"). This meant: - ❌ User provides "main" → check fails (should succeed if origin/main exists) - ✅ User provides "origin/main" → check succeeds ### The Fix Updated `check_remote_branch_exists()` in `crates/services/src/services/git.rs:1414-1428` to try both formats: 1. **First attempt**: Try the branch name as-is (handles "origin/main" format) 2. **Fallback**: Prepend default remote name (handles "main" format → "origin/main") This follows the same pattern used by `find_branch()`, `find_branch_type()`, and `check_branch_exists()` throughout the codebase. ### Complete Implementation The full pre-flight check implementation now includes: **Backend:** - ✅ Fetches from remote to get latest refs - ✅ Checks if target branch exists (handles both "main" and "origin/main" formats) - ✅ Returns typed error `CreatePrError::TargetBranchNotFound { branch }` - ✅ Handles auth errors during fetch → `CreatePrError::GitCliNotLoggedIn` - ✅ Handles missing git CLI → `CreatePrError::GitCliNotInstalled` **Frontend:** - ✅ Handles `target_branch_not_found` error type in CreatePRDialog - ✅ Displays localized error message with branch name - ✅ Translations added for all 4 locales (en, es, ja, ko) All checks pass! * Lint * Change pre-flight check for create PR (vibe-kanban 4f79fbc8) to use git ls-remote --branches to check for remote branche existence instead of libgit2. To do this add an appropriate method to crates/services/src/services/git/cli.rs and modify the preflight check. * Perfect! All checks pass. The implementation is now complete: ## Complete Implementation Summary ### What Was Built A pre-flight check for PR creation that verifies the target branch exists on the remote before attempting to create the pull request. ### Key Changes **Backend:** 1. **`check_remote_branch_exists()`** in `git.rs:1414-1428` - Checks if a branch exists remotely, handles both "main" and "origin/main" formats 2. **`fetch_and_check_branch_exists()`** in `git.rs:1430-1439` - Fetches from remote then checks existence, propagates errors 3. **`CreatePrError::TargetBranchNotFound`** in `task_attempts.rs:616` - New typed error variant with branch name 4. **Pre-flight check** in `create_github_pr()` in `task_attempts.rs:639-662` - Validates target branch exists, handles auth errors **Frontend:** 1. **Error handler** in `CreatePRDialog.tsx:187-195` - Displays localized error message 2. **Translations** in all 4 locales (en, es, ja, ko) - Localized error messages with branch name interpolation ### What Works - ✅ Detects missing target branches before push/PR creation - ✅ Handles "main" and "origin/main" branch name formats - ✅ Fails fast on auth errors during fetch - ✅ Returns typed errors the frontend can handle - ✅ Displays clear, localized error messages with the branch name - ✅ All checks pass (Rust clippy, TypeScript, type generation) |
||
|
|
f651c64f7d |
Perfect! I've successfully added a text wrap toggle to the frontend diff viewer. Here's a summary of the changes: (#1219)
## Changes Made ### 1. **State Management** (`frontend/src/stores/useDiffViewStore.ts:11-13,22-23,29`) - Added `wrapText` boolean state (defaults to `false`) - Added `setWrapText` action to update the state - Exported `useWrapTextDiff` hook for components to access the state ### 2. **UI Toggle Component** (`frontend/src/components/diff-view-switch.tsx:1,8,28-29,32,100-121`) - Imported `WrapText` icon from `lucide-react` - Added a new toggle group for the text wrap feature - The toggle appears alongside the existing view mode and whitespace toggles - Uses the same UI pattern as the "Ignore Whitespace" toggle - Includes tooltip with internationalization support ### 3. **Diff Viewer Integration** (`frontend/src/components/DiffCard.tsx:31,84,300`) - Imported and used the `useWrapTextDiff` hook - Connected the `wrapText` state to the `DiffView` component's `diffViewWrap` prop - The `DiffView` component now responds to the toggle state ## How It Works - The toggle button appears in the diff view controls with a `WrapText` icon - Clicking the toggle switches between wrapped and unwrapped text in the diff viewer - The state is managed globally via Zustand, so all diff viewers share the same wrap preference - The default is set to `false` (no wrapping), preserving the original behavior - The feature follows the existing architectural patterns for the ignore whitespace and view mode toggles The implementation is complete and ready to use! |
||
|
|
44b7f749c5 |
Allow auth redirect to non-localhost (#1346)
Allow non-localhost clients to complete OAuth. |
||
|
|
c2a10aaf72 |
fix: Copilot session resume (#1355)
GitHub Copilot CLI changed the the name of session files, which broke session resume. |
||
|
|
37f8f3c74f |
Gemini fixes (#1349)
* Fix gemini yolo * limit diff unchanged lines context to 3 lines * fix shell command parsing * remove the GeminiModel struct |
||
|
|
1933bb463c |
Decouple git from github errors (#1347)
* Decouple git from github errors
* Fix git error display (vibe-kanban 7352dadc)
After the last few commits git cli not logged in error does not get displayed to the user. Network tab shows this:
{
"success": false,
"data": null,
"error_data": {
"type": "git_cli_not_logged_in"
},
"message": null
}
|
||
|
|
037302c62f | Improved multi-process support of --mcp command (#1343) | ||
|
|
c375560353 | followup: Prefer runtime env variable VK_SHARED_API_BASE (#1342) | ||
|
|
f691fbd9cb | chore: bump version to 0.0.122 | ||
|
|
40252b6ea7 |
Bump codex (#1345)
* Done. Bumped codex from 0.58.0 to 0.60.1 in [codex.rs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/8d60-bump-codex/crates/executors/src/executors/codex.rs#L171). * Added `gpt-5.1-codex-max` model variant as a new `MAX` profile in [default_profiles.json](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/8d60-bump-codex/crates/executors/default_profiles.json#L62-L68). |
||
|
|
83602590e9 |
Droid agent (#1318)
* droid research (vibe-kanban 054135e9)
<droid-docs>
# Overview
> Non-interactive execution mode for CI/CD pipelines and automation scripts.
# Droid Exec (Headless CLI)
Droid Exec is Factory's headless execution mode designed for automation workflows. Unlike the interactive CLI, `droid exec` runs as a one-shot command that completes a task and exits, making it ideal for CI/CD pipelines, shell scripts, and batch processing.
## Summary and goals
Droid Exec is a one-shot task runner designed to:
* Produce readable logs, and structured artifacts when requested
* Enforce opt-in for mutations/command execution (secure-by-default)
* Fail fast on permission violations with clear errors
* Support simple composition for batch and parallel work
<CardGroup cols={2}>
<Card title="Non-Interactive" icon="terminal">
Single run execution that writes to stdout/stderr for CI/CD integration
</Card>
<Card title="Secure by Default" icon="lock">
Read-only by default with explicit opt-in for mutations via autonomy levels
</Card>
<Card title="Composable" icon="puzzle">
Designed for shell scripting, parallel execution, and pipeline integration
</Card>
<Card title="Clean Output" icon="file-export">
Structured output formats and artifacts for automated processing
</Card>
</CardGroup>
## Execution model
* Non-interactive single run that writes to stdout/stderr.
* Default is spec-mode: the agent is only allowed to execute read-only operations.
* Add `--auto` to enable edits and commands; risk tiers gate what can run.
CLI help (excerpt):
```
Usage: droid exec [options] [prompt]
Execute a single command (non-interactive mode)
Arguments:
prompt The prompt to execute
Options:
-o, --output-format <format> Output format (default: "text")
-f, --file <path> Read prompt from file
--auto <level> Autonomy level: low|medium|high
--skip-permissions-unsafe Skip ALL permission checks (unsafe)
-s, --session-id <id> Existing session to continue (requires a prompt)
-m, --model <id> Model ID to use
-r, --reasoning-effort <level> Reasoning effort: off|low|medium|high
--cwd <path> Working directory path
-h, --help display help for command
```
Supported models (examples):
* gpt-5-codex (default)
* gpt-5-2025-08-07
* claude-sonnet-4-20250514
* claude-opus-4-1-20250805
## Installation
<Steps>
<Step title="Install Droid CLI">
<CodeGroup>
```bash macOS/Linux theme={null}
curl -fsSL https://app.factory.ai/cli | sh
```
```powershell Windows theme={null}
irm https://app.factory.ai/cli/windows | iex
```
</CodeGroup>
</Step>
<Step title="Get Factory API Key">
Generate your API key from the [Factory Settings Page](https://app.factory.ai/settings/api-keys)
</Step>
<Step title="Set Environment Variable">
Export your API key as an environment variable:
```bash theme={null}
export FACTORY_API_KEY=fk-...
```
</Step>
</Steps>
## Quickstart
* Direct prompt:
* `droid exec "analyze code quality"`
* `droid exec "fix the bug in src/main.js" --auto low`
* From file:
* `droid exec -f prompt.md`
* Pipe:
* `echo "summarize repo structure" | droid exec`
* Session continuation:
* `droid exec --session-id <session-id> "continue with next steps"`
## Autonomy Levels
Droid exec uses a tiered autonomy system to control what operations the agent can perform. By default, it runs in read-only mode, requiring explicit flags to enable modifications.
### DEFAULT (no flags) - Read-only Mode
The safest mode for reviewing planned changes without execution:
* ✅ Reading files or logs: cat, less, head, tail, systemctl status
* ✅ Display commands: echo, pwd
* ✅ Information gathering: whoami, date, uname, ps, top
* ✅ Git read operations: git status, git log, git diff
* ✅ Directory listing: ls, find (without -delete or -exec)
* ❌ No modifications to files or system
* **Use case:** Safe for reviewing what changes would be made
```bash theme={null}
# Analyze and plan refactoring without making changes
droid exec "Analyze the authentication system and create a detailed plan for migrating from session-based auth to OAuth2. List all files that would need changes and describe the modifications required."
# Review code quality and generate report
droid exec "Review the codebase for security vulnerabilities, performance issues, and code smells. Generate a prioritized list of improvements needed."
# Understand project structure
droid exec "Analyze the project architecture and create a dependency graph showing how modules interact with each other."
```
### `--auto low` - Low-risk Operations
Enables basic file operations while blocking system changes:
* ✅ File creation/editing in project directories
* ❌ No system modifications or package installations
* **Use case:** Documentation updates, code formatting, adding comments
```bash theme={null}
# Safe file operations
droid exec --auto low "add JSDoc comments to all functions"
droid exec --auto low "fix typos in README.md"
```
### `--auto medium` - Development Operations
Operations that may have significant side effects, but these side effects are typically harmless and straightforward to recover from.
Adds common development tasks to low-risk operations:
* Installing packages from trusted sources: npm install, pip install (without sudo)
* Network requests to trusted endpoints: curl, wget to known APIs
* Git operations that modify local repositories: git commit, git checkout, git pull (but not git push)
* Building code with tools like make, npm run build, mvn compile
* ❌ No git push, sudo commands, or production changes
* **Use case:** Local development, testing, dependency management
```bash theme={null}
# Development tasks
droid exec --auto medium "install deps, run tests, fix issues"
droid exec --auto medium "update packages and resolve conflicts"
```
### `--auto high` - Production Operations
Commands that may have security implications such as data transfers between untrusted sources or execution of unknown code, or major side effects such as irreversible data loss or modifications of production systems/deployments.
* Running arbitrary/untrusted code: curl | bash, eval, executing downloaded scripts
* Exposing ports or modifying firewall rules that could allow external access
* Git push operations that modify remote repositories: git push, git push --force
* Irreversible actions to production deployments, database migrations, or other sensitive operations
* Commands that access or modify sensitive information like passwords or keys
* ❌ Still blocks: sudo rm -rf /, system-wide changes
* **Use case:** CI/CD pipelines, automated deployments
```bash theme={null}
# Full workflow automation
droid exec --auto high "fix bug, test, commit, and push to main"
droid exec --auto high "deploy to staging after running tests"
```
### `--skip-permissions-unsafe` - Bypass All Checks
<Warning>
DANGEROUS: This mode allows ALL operations without confirmation. Only use in completely isolated environments like Docker containers or throwaway VMs.
</Warning>
* ⚠️ Allows ALL operations without confirmation
* ⚠️ Can execute irreversible operations
* Cannot be combined with --auto flags
* **Use case:** Isolated environments
```bash theme={null}
# In a disposable Docker container for CI testing
docker run --rm -v $(pwd):/workspace alpine:latest sh -c "
apk add curl bash &&
curl -fsSL https://app.factory.ai/cli | sh &&
droid exec --skip-permissions-unsafe 'Install all system dependencies, modify system configs, run integration tests that require root access, and clean up test databases'
"
# In ephemeral GitHub Actions runner for rapid iteration
# where the runner is destroyed after each job
droid exec --skip-permissions-unsafe "Modify /etc/hosts for test domains, install custom kernel modules, run privileged container tests, and reset network interfaces"
# In a temporary VM for security testing
droid exec --skip-permissions-unsafe "Run penetration testing tools, modify firewall rules, test privilege escalation scenarios, and generate security audit reports"
```
### Fail-fast Behavior
If a requested action exceeds the current autonomy level, droid exec will:
1. Stop immediately with a clear error message
2. Return a non-zero exit code
3. Not perform any partial changes
This ensures predictable behavior in automation scripts and CI/CD pipelines.
## Output formats and artifacts
Droid exec supports three output formats for different use cases:
### text (default)
Human-readable output for direct consumption or logs:
```bash theme={null}
$ droid exec --auto low "create a python file that prints 'hello world'"
Perfect! I've created a Python file named `hello_world.py` in your home directory that prints 'hello world' when executed.
```
### json
Structured JSON output for parsing in scripts and automation:
```bash theme={null}
$ droid exec "summarize this repository" --output-format json
{
"type": "result",
"subtype": "success",
"is_error": false,
"duration_ms": 5657,
"num_turns": 1,
"result": "This is a Factory documentation repository containing guides for CLI tools, web platform features, and onboarding procedures...",
"session_id": "8af22e0a-d222-42c6-8c7e-7a059e391b0b"
}
```
Use JSON format when you need to:
* Parse the result in a script
* Check success/failure programmatically
* Extract session IDs for continuation
* Process results in a pipeline
### debug
Streaming messages showing the agent's execution in real-time:
```bash theme={null}
$ droid exec "run ls command" --output-format debug
{"type":"message","role":"user","text":"run ls command"}
{"type":"message","role":"assistant","text":"I'll run the ls command to list the contents..."}
{"type":"tool_call","toolName":"Execute","parameters":{"command":"ls -la"}}
{"type":"tool_result","value":"total 16\ndrwxr-xr-x@ 8 user staff..."}
{"type":"message","role":"assistant","text":"The ls command has been executed successfully..."}
```
Debug format is useful for:
* Monitoring agent behavior
* Troubleshooting execution issues
* Understanding tool usage patterns
* Real-time progress tracking
For automated pipelines, you can also direct the agent to write specific artifacts:
```bash theme={null}
droid exec --auto low "Analyze dependencies and write to deps.json"
droid exec --auto low "Generate metrics report in CSV format to metrics.csv"
```
## Working directory
* Use `--cwd` to scope execution:
```
droid exec --cwd /home/runner/work/repo "Map internal packages and dump graphviz DOT to deps.dot"
```
## Models and reasoning effort
* Choose a model with `-m` and adjust reasoning with `-r`:
```
droid exec -m claude-sonnet-4-20250514 -r medium -f plan.md
```
## Batch and parallel patterns
Shell loops (bounded concurrency):
```bash theme={null}
# Process files in parallel (GNU xargs -P)
find src -name "*.ts" -print0 | xargs -0 -P 4 -I {} \
droid exec --auto low "Refactor file: {} to use modern TS patterns"
```
Background job parallelization:
```bash theme={null}
# Process multiple directories in parallel with job control
for path in packages/ui packages/models apps/factory-app; do
(
cd "$path" &&
droid exec --auto low "Run targeted analysis and write report.md"
) &
done
wait # Wait for all background jobs to complete
```
Chunked inputs:
```bash theme={null}
# Split large file lists into manageable chunks
git diff --name-only origin/main...HEAD | split -l 50 - /tmp/files_
for f in /tmp/files_*; do
list=$(tr '\n' ' ' < "$f")
droid exec --auto low "Review changed files: $list and write to review.json"
done
rm /tmp/files_* # Clean up temporary files
```
Workflow Automation (CI/CD):
```yaml theme={null}
# Dead code detection and cleanup suggestions
name: Code Cleanup Analysis
on:
schedule:
- cron: '0 1 * * 0' # Weekly on Sundays
workflow_dispatch:
jobs:
cleanup-analysis:
strategy:
matrix:
module: ['src/components', 'src/services', 'src/utils', 'src/hooks']
steps:
- uses: actions/checkout@v4
- run: droid exec --cwd "${{ matrix.module }}" --auto low "Identify unused exports, dead code, and deprecated patterns. Generate cleanup recommendations in cleanup-report.md"
```
## Unique usage examples
License header enforcer:
```bash theme={null}
git ls-files "*.ts" | xargs -I {} \
droid exec --auto low "Ensure {} begins with the Apache-2.0 header; add it if missing"
```
API contract drift check (read-only):
```bash theme={null}
droid exec "Compare openapi.yaml operations to our TypeScript client methods and write drift.md with any mismatches"
```
Security sweep:
```bash theme={null}
droid exec --auto low "Run a quick audit for sync child_process usage and propose fixes; write findings to sec-audit.csv"
```
## Exit behavior
* 0: success
* Non-zero: failure (permission violation, tool error, unmet objective). Treat non-zero as failed in CI.
## Best practices
* Favor `--auto low`; keep mutations minimal and commit/push in scripted steps.
* Avoid `--skip-permissions-unsafe` unless fully sandboxed.
* Ask the agent to emit artifacts your pipeline can verify.
* Use `--cwd` to constrain scope in monorepos.
</droid-docs>
Use the oracle to research how we support custom executors.
AMP and Claude Code would likely be good references here as I believe that they both operate via JSON.
Save your findings in a single markdown file.
* begin droid
* add plan
* droid implementation (vibe-kanban 90e6c8f6)
Read tasks/droid-agent/plan.md and execute the plan.
* document droid (vibe-kanban 0a7f8590)
we have introduced a new coding agent
Installation instructions are at https://factory.ai/product/cli
We expect that users have the `droid` cli installed and that they have logged in.
docs/supported-coding-agents.mdx
There may also be other docs or references.
* red gh action (vibe-kanban f0c8b6c4)
Run cargo fmt --all -- --check
cargo fmt --all -- --check
npm run generate-types:check
cargo test --workspace
cargo clippy --all --all-targets -- -D warnings
the checks step is failing, can you see what's up with the rust codebase and resolve it?
* droid | settings bug (vibe-kanban 7deec8df)
We have a new coding agent called Droid and it has a variety of different settings including the autonomy level and we default this to medium and users can update this by going to settings and then using the drop down to change it and then hitting the save button. And this works, however, when users return back to settings the displayed autonomy level is reset to medium rather than the correct level. So can you investigate why this is happening and plan how we can improve it, how we can verify it, do we need to introduce some logging, other things to consider. Write up your plan in a new markdown file.
* glob
* tool call parsing & display (vibe-kanban e3f65a74)
droid.rs has `fn map_tool_to_action`
The problem is that we're doing a poor job at displaying these tool calls e.g. glob. In `claude.rs`, we use `ClaudeToolData`, a struct that matches the real JSON data. Once we do that, we have a type safe way to map tool calls to the `ActionType` struct.
You can run `droid exec --output-format=stream-json --auto medium "YOUR MESSAGE MERE"` in a temporary directory to instruct the agent to generate custom outputs in case you need more sample data.
I just added glob.jsonl under droid-json, there are other json files in there too.
I recommend using sub agents as some of these files (e.g. claude.rs) are large.
cursor.rs might also be a useful reference.
You're done once we properly handle these tools.
* show droid model (vibe-kanban 8fdbc630)
The first JSON object emitted from the droid executor is a system message with a `model` field. We should capture and display this.
I believe that we're already doing something similar with Codex.
Here's a sample system message:
{"type":"system","subtype":"init","cwd":"/Users/britannio/projects/vibe-kanban","session_id":"59a75629-c0c4-451f-a3c7-8e9eab05484a","tools":["Read","LS","Execute","Edit","MultiEdit","ApplyPatch","Grep","Glob","Create","ExitSpecMode","WebSearch","TodoWrite","FetchUrl","slack_post_message"],"model":"gpt-5-codex"}
* reliable apply patch display (vibe-kanban 3710fb65)
The crates/executors/src/executors/droid.rs ApplyPatch tool call contains an `input` string which isn't very helpful, but the tool call result is a JSON object with a `value` object with the fields success, content, diff, and file_path.
Here's a parsed example of `value`:
{
"success": true,
"content": "def bubble_sort(arr):\n \"\"\"\n Bubble Sort Algorithm\n Time Complexity: O(n^2)\n Space Complexity: O(1)\n\n Repeatedly steps through the list, compares adjacent elements and swaps them\n if they are in the wrong order.\n \"\"\"\n n = len(arr)\n arr = arr.copy() # Create a copy to avoid modifying the original\n\n for i in range(n):\n # Flag to optimize by stopping if no swaps occur\n swapped = False\n\n for j in range(0, n - i - 1):\n if arr[j] > arr[j + 1]:\n arr[j], arr[j + 1] = arr[j + 1], arr[j]\n swapped = True\n\n # If no swaps occurred, array is already sorted\n if not swapped:\n break\n\n return arr\n\n\ndef insertion_sort(arr):\n \"\"\"\n Insertion Sort Algorithm\n Time Complexity: O(n^2)\n Space Complexity: O(1)\n\n Builds the sorted portion of the array one element at a time by inserting\n each element into its correct position.\n \"\"\"\n arr = arr.copy() # Create a copy to avoid modifying the original\n\n for i in range(1, len(arr)):\n key = arr[i]\n j = i - 1\n\n while j >= 0 and arr[j] > key:\n arr[j + 1] = arr[j]\n j -= 1\n\n arr[j + 1] = key\n\n return arr\n\n\nif __name__ == \"__main__\":\n # Example usage\n test_array = [64, 34, 25, 12, 22, 11, 90]\n\n print(\"Original array:\", test_array)\n print(\"\\nBubble Sort result:\", bubble_sort(test_array))\n print(\"Insertion Sort result:\", insertion_sort(test_array))\n\n # Test with different arrays\n print(\"\\n--- Additional Tests ---\")\n test_cases = {\n \"Reverse sorted\": [5, 4, 3, 2, 1],\n \"Empty array\": [],\n \"Already sorted\": [1, 2, 3, 4, 5],\n }\n\n for description, case in test_cases.items():\n print(f\"{description} (Bubble):\", bubble_sort(case))\n print(f\"{description} (Insertion):\", insertion_sort(case))\n",
"diff": "--- previous\t\n+++ current\t\n@@ -26,14 +26,46 @@\n return arr\n \n \n+def insertion_sort(arr):\n+ \"\"\"\n+ Insertion Sort Algorithm\n+ Time Complexity: O(n^2)\n+ Space Complexity: O(1)\n+\n+ Builds the sorted portion of the array one element at a time by inserting\n+ each element into its correct position.\n+ \"\"\"\n+ arr = arr.copy() # Create a copy to avoid modifying the original\n+\n+ for i in range(1, len(arr)):\n+ key = arr[i]\n+ j = i - 1\n+\n+ while j >= 0 and arr[j] > key:\n+ arr[j + 1] = arr[j]\n+ j -= 1\n+\n+ arr[j + 1] = key\n+\n+ return arr\n+\n+\n if __name__ == \"__main__\":\n # Example usage\n test_array = [64, 34, 25, 12, 22, 11, 90]\n \n print(\"Original array:\", test_array)\n print(\"\\nBubble Sort result:\", bubble_sort(test_array))\n+ print(\"Insertion Sort result:\", insertion_sort(test_array))\n \n # Test with different arrays\n print(\"\\n--- Additional Tests ---\")\n- print(\"Reverse sorted:\", bubble_sort([5, 4, 3, 2, 1]))\n- print(\"Empty array:\", bubble_sort([]))\n+ test_cases = {\n+ \"Reverse sorted\": [5, 4, 3, 2, 1],\n+ \"Empty array\": [],\n+ \"Already sorted\": [1, 2, 3, 4, 5],\n+ }\n+\n+ for description, case in test_cases.items():\n+ print(f\"{description} (Bubble):\", bubble_sort(case))\n+ print(f\"{description} (Insertion):\", insertion_sort(case))",
"file_path": "/Users/britannio/projects/droid-simple/sorting_algorithms.py"
}
This formatting should be deterministic and thus we can use it to show more informative tool call data.
The first thing to understand is if this will naturally fit with the current architecture, as we only reliably know how the file has changed (and what the target file was) after receiving the tool call result.
* droid failed tool call handling (vibe-kanban bd7feddb)
crates/executors/src/executors/droid.rs
droid-json/insufficient-perms.jsonl
the insufficient-perms file contains the JSON output log of a run where it runs a command to create a file but the tool call fails due to a permission error.
I'd expect that the failed tool result would be correlated with the tool call and thus i'd see an ARGS block and a RESULTS block within the tool call on the front-end.
Instead, I see the tool call only with the ARGS block, then I see a separate UI element with the JSON tool result as if it failed to be correlated.
Firstly, I want to follow TDD by creating a failing test that confirms this behaviour. It might be hard though because we haven't designed the code in droid.rs with testability in mind.
Lets first analyse the code to consider if it's already testable or if we need to do any refactoring & introduce harnesses etc.
My perspective of the coding agent is that we send it a command, and it streams JSON objects one by one so some form of reducer pattern seems natural (previous list of json objects + previous state + new json object => new state). Either 'new state' or 'new delta'.
When we resume a session, it will emit a system message object, then a message object with role user (repeating what we sent it), then the new actions that it takes.
* droid default (vibe-kanban 2f8a19cc)
the default autonomy level is currently medium. Lets change it to the highest (unsafe)
* droid globbing rendering (vibe-kanban 76d372ea)
See droid-json/glob.jsonl
Notice the `patterns` field. Unfortunately, we seems to not be using this data as glob tool calls are being rendered exclusively via a file name of some sort rather than `Globbing README.md, readme.md,docs/**,*.md`
Use the oracle to investigate this.
* droid todo list text (vibe-kanban b1bdeffc)
Use the text 'TODO list updated' for the droid agent when it makes a change to the todo list.
* droid workspace path (vibe-kanban 0486b74a)
See how claude.rs uses worktree_path (from normalize_logs).
We should be doing the same for the droid executor so that the tool calls we generate have relative paths.
* mcp settings (vibe-kanban 2031d8f4)
Quick fix: Filter that agent from the dropdown in the frontend.
// In McpSettings.tsx, line 282-289
<SelectContent>
{profiles &&
Object.entries(profiles)
.filter(([key]) => key !== 'DROID') // or whatever the agent name is
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([profileKey]) => (
<SelectItem key={profileKey} value={profileKey}>
{profileKey}
</SelectItem>
))}
</SelectContent>
we need to temporarily hide droid as it doesn't support mcp yet.
* clean up (vibe-kanban 6b1a8e2e)
remove all references to 'britannio' from the droid module.
* delete droid json
* droid agent code review (vibe-kanban 6820ffd1)
We added Droid to crates/services/src/services/config/versions/v1.rs but presumably we should've used the latest reasonable version. See what we used for Copilot.
Delete docs/adr-droid-architecture.md
Delete docs/droid-improvements-summary.md
docs/supported-coding-agents.mdx the default was medium, it's now skip-permissions-unsafe
Delete the tasks/ folder
* remove unnecessary v1 change
* updated droid.json schema
* tweak command
* droid model suggestions (vibe-kanban 120f87d2)
crates/executors/src/executors/droid/types.rs
Valid model IDs are:
gpt-5-codex OpenAI GPT-5-Codex (Auto)
claude-sonnet-4-5-20250929 Claude Sonnet 4.5
gpt-5-2025-08-07 OpenAI GPT-5
claude-opus-4-1-20250805 Claude Opus 4.1
claude-haiku-4-5-20251001 Claude Haiku 4.5
glm-4.6 Droid Core (GLM-4.6)
We currently mention gpt-5-codex, claude-sonnet-4
* remove dead code
* droid automated testing (vibe-kanban f836b4a4)
lets start brainstorming this, starting with tests in crates/executors/src/executors/droid/types.rs to ensure that we correctly generate a command
* create exec_command_with_prompt
* Add logging to error paths in action_mapper.rs (vibe-kanban 76cc5d71)
Add tracing logging (warn/error) to error paths in `crates/executors/src/executors/droid/action_mapper.rs` following existing logging patterns in the codebase.
Key locations:
- Line 32-35: DroidToolData parsing failure (currently silent)
- Any other error paths that swallow errors
Use `tracing::warn!` with structured fields for context (tool_name, error details, etc.)
* droid automated testing (DroidJSON -> NormalizedEntry) (vibe-kanban cf325d24)
We have example agent from /Users/britannio/Downloads/droid-json
Read crates/executors/src/executors/droid/events.rs
Use the oracle to plan tests that we could introduce.
* preserve timestamp
* droid reasoning effort (vibe-kanban 47dae2db)
in settings, we're showing a dropdown for the droid autonomy level. We should be doing the same for the reasoning level. It should default to being empty if possible.
* droid path (vibe-kanban d8370535)
Droid file edits (presumably ApplyPatch?) aren't using relative paths. E.g. i'm seeing `/private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban-dev/worktrees/11dc-setup/next.config.mjs`
* fix warning
* fix warning
* whitespace update
* DomainEvent -> LogEvent
* remove msg store stream -> line converter
* normalise the diff generated when the droid ApplyPatch tool call is
parsed
* refactor process_event to mutate a reference to ProcessorState
* remove EntryIndexProvider abstraction
* remove dead code
* remove JSON indirection when invoking extract_path_from_patch
* converting DroidJson -> LogEvent produces Option instead of Vec
DroidJson mapping tests removed in favour of snapshot testing delete
emit_patches (now redundant) update match syntax in
compute_updated_action_type make process_event a member of
ProcessorState
* simplify droid build_command_builder
* simplify droid types tests
* remove droid type tests
* rename events.rs -> log_event_converter.rs
rename patch_emitter -> patch_converter
remove ParsedLine indirection from processor.rs
handle Edit, MultiEdit, and Create tool calls (only used by some models like claude)
move action mapper logic to log_event_converter
introduce a claude snapshot
update snapshots
* add error log for failed parsing of DroidJson
* update snapshots
* Fix clippy warnings in droid executor
- Change &String to &str in extract_path_from_patch
- Rename to_patch to process_event for correct self convention
Amp-Thread-ID: https://ampcode.com/threads/T-81d4f5ac-6d3a-4da5-9799-de724f3df1e3
Co-authored-by: Amp <amp@ampcode.com>
* update cargo lock
* droid tool call result parsing (vibe-kanban 514d27de)
the droid executor has a regression where the `droid exec` command is no longer producing an `id` field for tool_result messages. Fortunately, in most cases, it's safe to stick to FIFO behaviour whereby if we get a tool result, we can match it with the earliest tool call. This won't always work but it's a reasonable solution for the next few days while the droid team fixes their executor.
Start by using the oracle to trace and understand the codepaths involved, and to make a plan. We likely need to update the DroidJson struct so that the tool call result id becomes optional.
To test this, we can take an existing snapshot test and create a variant of it without ids in the tool call results, and see if we still produce equivalent log events.
* refactor: collapse nested if statements in log_event_converter
Amp-Thread-ID: https://ampcode.com/threads/T-b9ad8aac-0fd5-44c5-b2f8-317d79b623a6
Co-authored-by: Amp <amp@ampcode.com>
* format
* Cleanup droid executor implementation
* Implement session forking
* linter
---------
Co-authored-by: Britannio Jarrett <britanniojarrett@gmail.com>
Co-authored-by: Test User <test@example.com>
Co-authored-by: Amp <amp@ampcode.com>
|
||
|
|
a3c134b4a6 | Done. Version bumped to 0.0.1763625676-g928988. (#1344) | ||
|
|
853b178ebf | chore: bump version to 0.0.121 | ||
|
|
9a5323b3b4 |
Prefer runtime env variable VK_SHARED_API_BASE (#1340)
Enables testing a pre-release with a dev version of remote. |
||
|
|
6e5cb34f7e |
Better worktree errors (#1338)
* Info log if first create fails, properly clean up after first fail * Show stdout on git cli error * Fix swapped stderr/stdout |
||
|
|
84454b54a1 | JWT: separate access tokens and refresh tokens (#1315) | ||
|
|
f3d963c285 |
Add org events (vibe-kanban) (#1339)
* Excellent! All tests pass. Let me create a summary of the changes:
## Summary
I've successfully added analytics events for organization-related actions in the Vibe Kanban codebase. Here's what was implemented:
### Changes Made
**1. `crates/server/src/routes/organizations.rs`:**
- Added `Deployment` trait import
- **Organization Created** (`create_organization` at line 90-110):
- Event: `"organization_created"`
- Properties: `org_id`, `is_personal`
- **Invitation Created** (`create_invitation` at line 134-155):
- Event: `"invitation_created"`
- Properties: `invitation_id`, `org_id`, `role`
- ✅ No sensitive data (invitee email excluded)
**2. `crates/server/src/routes/projects.rs`:**
- **Project Linked to Remote** (`apply_remote_project_link` at line 168-197):
- Event: `"project_linked_to_remote"`
- Properties: `project_id`, `link_type` ("existing" or "new")
- Tracks both linking to existing projects and creating new remote projects
- Added `link_type` parameter to distinguish between the two use cases
### Implementation Details
- All events follow the existing PostHog analytics pattern using `deployment.track_if_analytics_allowed()`
- Events are tracked **after** successful operations, **before** returning responses
- UUIDs are converted to strings with `.to_string()`
- Event names use snake_case convention
- No sensitive data (like invitee emails) is tracked
- All code compiles successfully and passes existing tests ✅
* Excellent! I've successfully removed the `link_type` parameter. Here's the updated summary of the changes:
## Final Summary
I've successfully added analytics events for organization-related actions and addressed your feedback. Here's what was implemented:
### Changes Made
**1. `crates/server/src/routes/organizations.rs`:**
- Added `Deployment` trait import
- **Organization Created** (line 90-109):
- Event: `"organization_created"`
- Properties: `org_id`, `is_personal`
- **Invitation Created** (line 124-144):
- Event: `"invitation_created"`
- Properties: `invitation_id`, `org_id`, `role`
- ✅ No sensitive data (invitee email excluded)
**2. `crates/server/src/routes/projects.rs`:**
- **Project Linked to Remote** (line 168-195):
- Event: `"project_linked_to_remote"`
- Properties: `project_id` only
- Simplified analytics - removed `link_type` parameter per your feedback
### Implementation Details
- All events follow the existing PostHog analytics pattern using `deployment.track_if_analytics_allowed()`
- Events are tracked **after** successful operations, **before** returning responses
- UUIDs are converted to strings with `.to_string()`
- Event names use snake_case convention
- No sensitive data tracked
- All code compiles successfully ✅
* Perfect! I've successfully removed the `is_personal` property. Here's the final summary:
## Updated Summary
I've successfully added analytics events for organization-related actions and incorporated all your feedback. Here's the final implementation:
### Changes Made
**1. `crates/server/src/routes/organizations.rs`:**
- Added `Deployment` trait import
- **Organization Created** (line 90-109):
- Event: `"organization_created"`
- Properties: `org_id` only
- **Invitation Created** (line 124-144):
- Event: `"invitation_created"`
- Properties: `invitation_id`, `org_id`, `role`
- ✅ No sensitive data (invitee email excluded)
**2. `crates/server/src/routes/projects.rs`:**
- **Project Linked to Remote** (line 168-195):
- Event: `"project_linked_to_remote"`
- Properties: `project_id` only
### Implementation Details
- All events follow the existing PostHog analytics pattern using `deployment.track_if_analytics_allowed()`
- Events are tracked **after** successful operations, **before** returning responses
- UUIDs are converted to strings with `.to_string()`
- Event names use snake_case convention
- No sensitive data tracked
- Minimal properties tracked per your feedback
- All code compiles successfully ✅
|
||
|
|
23b0d9c0af | Fix ts compile (#1337) | ||
|
|
5ac6c2b462 |
I've removed the touch-pan-y class from the Kanban board wrapper in frontend/src/pages/ProjectTasks.tsx. This enables horizontal scrolling on touch devices while maintaining vertical scrolling, which solves the issue. (#1334)
I also ran the type checks to ensure no regressions, and everything passed. The provided file path `crates/remote/src/db/project_tasks.rs` was not relevant to the UI scrolling issue, so no changes were made there. |
||
|
|
4b1af8cdc5 |
Show editor availability (vibe-kanban) (#1325)
* Perfect! I've successfully refactored the editor opening code to use the `CommandBuilder` pattern. Here's a summary of the changes: - Added `use executors::command::CommandBuilder;` - Changed return type from `Vec<String>` to `CommandBuilder` - Now returns a proper `CommandBuilder` that handles shell word splitting correctly - Supports quoted strings in custom commands (via `shlex` on Unix, `winsplit` on Windows) - Uses `CommandBuilder` pattern: `build_initial()` → `into_resolved()` - Resolves executables properly on **both Unix and Windows** (previously only Windows had resolution) - Better error messages that show which executable couldn't be found - Maps `ExecutorError` to `io::Error` for consistency with the function signature ✅ **Consistent cross-platform behavior**: Unix now also resolves executables properly ✅ **Sophisticated PATH resolution**: Uses login shell refresh logic for finding executables ✅ **Proper shell word splitting**: Handles quoted strings correctly in custom commands ✅ **Better error messages**: Shows exactly which executable couldn't be found ✅ **Follows established patterns**: Uses the same proven pattern as other executors in the codebase All checks pass: compilation, tests, and Clippy linting. The code is ready! Perfect! All changes have been successfully implemented and tested. Here's what was done: - Changed from: `Result<ResponseJson<ApiResponse<OpenEditorResponse>>, StatusCode>` - Changed to: `Result<ResponseJson<ApiResponse<OpenEditorResponse>>, ApiError>` - Changed from: `Err(StatusCode::INTERNAL_SERVER_ERROR)` (generic 500 error) - Changed to: `Err(ApiError::Io(e))` (passes actual error message) Now when the editor command fails (e.g., executable not found), the API will return a proper error response with the actual error message like: - `"IoError: Editor command not found: Executable 'cursor' not found in PATH"` This matches the pattern already used in `task_attempts.rs` and provides meaningful feedback to the frontend, which can display the error to users or fall back to the editor selection dialog. All checks pass: compilation, TypeScript type checking, and Clippy linting! Perfect! All changes have been successfully implemented and tested. Here's a summary: - New `EditorOpenError` enum with `ExecutableNotFound` variant - Contains structured fields: `executable` (the command that wasn't found) and `editor_type` (the configured editor) - Exports to TypeScript with discriminated union type - Changed `open_file()` return type: `Result<Option<String>, io::Error>` → `Result<Option<String>, EditorOpenError>` - Changed `spawn_local()` return type: `io::Result<()>` → `Result<(), EditorOpenError>` - Maps `ExecutorError::ExecutableNotFound` to structured `EditorOpenError::ExecutableNotFound` - Removed unused `io` import - Added `EditorOpen(#[from] EditorOpenError)` variant - Maps to `StatusCode::BAD_REQUEST` (400) instead of 500 - Returns proper error type: `"EditorOpenError"` - **`crates/server/src/routes/projects.rs:452`**: Changed from `ApiError::Io(e)` to `ApiError::EditorOpen(e)` - **`crates/server/src/routes/task_attempts.rs:965`**: Changed from generic `TaskAttemptError::ValidationError` to `ApiError::EditorOpen(e)` ```typescript export type EditorOpenError = { "type": "executable_not_found", executable: string, editor_type: string, }; ``` Now when an editor executable isn't found, the frontend receives: ```json { "type": "executable_not_found", "executable": "cursor", "editor_type": "CURSOR" } ``` Instead of a generic 500 error. This allows the frontend to: - Show specific error messages ("Cursor not found in PATH") - Suggest alternative editors - Provide installation links or PATH setup instructions - Offer to open the editor settings dialog All checks pass: compilation, TypeScript type checking, Clippy linting, and tests! Cleanup script changes for task attempt f9923e07-9b3b-4d18-b4d1-d4235cf0e12d * Refactor editor config (vibe-kanban a60c079b) Currently edit config is defined in crates/services/src/services/config/versions/v2.rs, we should consider moving it into a module instead. Weigh pros and cons, best practices and the current architecture * Review editor refactor (vibe-kanban 829ba3e5) Review the last 5 commits There's a rebase conflict in `GeneralSettings.tsx` that needs resolution. The conflict is in the imports: **Conflict (lines 41-49):** - **Your branch (HEAD)**: Imports from `ThemeProvider` and `ConfigProvider` (PascalCase) - **Main branch**: Imports from `theme-provider` and `config-provider` (kebab-case) + adds new editor availability features **Resolution needed:** Keep the main branch version because it: 1. Uses the newer kebab-case file naming convention 2. Adds `useEditorAvailability` and `EditorAvailabilityIndicator` features that complement your error handling work The resolved imports should be: ```typescript import { useEditorAvailability } from '@/hooks/useEditorAvailability'; import { EditorAvailabilityIndicator } from '@/components/EditorAvailabilityIndicator'; import { useTheme } from '@/components/theme-provider'; import { useUserSystem } from '@/components/config-provider'; ``` Would you like me to resolve this conflict and continue the rebase? Show available editors at startup (vibe-kanban 9f1ea85f) When onboarding, show a green checkmark next to installed editors. Use the editor struct refactored in the last 6 commits to make it work. Check eveyer editor in the enum at vk startup. Mkae sure editors being unailable does NOT break anything Fix imports after rebase - use PascalCase for ThemeProvider and ConfigProvider Perfect! All changes complete. Let me create a summary: ✅ **Changes made:** - Added `CheckEditorAvailabilityQuery::decl()` - Added `CheckEditorAvailabilityResponse::decl()` New types exported: ```typescript export type CheckEditorAvailabilityQuery = { editor_type: EditorType }; export type CheckEditorAvailabilityResponse = { available: boolean }; ``` - Added import for `CheckEditorAvailabilityResponse` - Updated `checkEditorAvailability` method: - Parameter type: `string` → `EditorType` (type-safe enum) - Return type: `{ available: boolean }` → `CheckEditorAvailabilityResponse` - ✅ Full type safety for editor availability checking - ✅ Frontend uses typed `EditorType` enum instead of strings - ✅ Consistent with other query/response type patterns - ✅ All checks pass (TypeScript + Rust compilation) The editor availability feature now has complete type safety from backend to frontend! * Fix i18n (vibe-kanban 57188642) For new editory avilability added in the last 3 commits. Run @scripts/check-i18n.sh until it passes. Make sure to check the script and set GITHUB_BASE_REF to main * Fix import: use github not github_service after rebase |
||
|
|
85690d6ac9 |
Cleanup dead code (#1336)
* Remove unused delete file endpoint, move test helpers to test files Fix missing git id in tests * Remove unused gh cli methods * Remove unused replace_process * Fix open editor exports, remove unused struct Fix compile * Remove unused get_tasks endpoint Re-add get tasks, used by mcp * Remove unused get_execution_processes endpoint * Remove unused get tag endpoint |
||
|
|
20b8de95d2 |
I have successfully updated the amp version in crates/executors/src/executors/amp.rs to 0.0.1763539290-g33c1d8. (#1333)
Verified the changes by running `cargo check -p executors`, which completed successfully. |
||
|
|
44351a8931 |
refactor: unify Git and Github interfaces (#1327)
* unify git and github interfaces * move test helpers into test files * Update crates/services/src/services/git.rs Co-authored-by: Alex Netsch <alex@bloop.ai> * Update crates/services/src/services/git.rs Co-authored-by: Alex Netsch <alex@bloop.ai> --------- Co-authored-by: Alex Netsch <alex@bloop.ai> |
||
|
|
4e6dc1790b |
tags in showcase (vibe-kanban) (#1268)
* Done! I've added the 5th slide for the tags feature: 1. Added the slide configuration in [showcases.ts](file:///private/var/folders/xw/pvvt9zw954zbk1304cvjlnz00000gn/T/vibe-kanban/worktrees/20bc-tags-in-showcase/frontend/src/config/showcases.ts) with the video URL 2. Added English translations for the tags feature in [tasks.json](file:///private/var/folders/xw/pvvt9zw954zbk1304cvjlnz00000gn/T/vibe-kanban/worktrees/20bc-tags-in-showcase/frontend/src/i18n/locales/en/tasks.json) The showcase now has 5 slides with the tags feature explaining how users can save custom prompts and embed them in tasks or follow-ups. * Done! Updated the video URL and added translations to all locales: - Updated video URL in [showcases.ts](file:///private/var/folders/xw/pvvt9zw954zbk1304cvjlnz00000gn/T/vibe-kanban/worktrees/20bc-tags-in-showcase/frontend/src/config/showcases.ts) - Added English translations - Added Spanish translations - Added Japanese translations - Added Korean translations --------- Co-authored-by: Vibe Kanban <noreply@vibekanban.com> |
||
|
|
050d832dad | chore: bump version to 0.0.120 | ||
|
|
7fb00530c5 |
I have applied the fix to frontend/src/components/dialogs/tasks/CreateAttemptDialog.tsx. (#1329)
The new logic checks if the `latestAttempt`'s executor matches your configured default executor. If it does, it applies your configured variant (e.g. `VARIANT1`) instead of defaulting to `null`. If the executors differ, it safely falls back to the default variant. This ensures that when you create a new attempt on a task where you previously used your preferred agent, your preferred variant is now correctly pre-selected. |
||
|
|
078554b5c7 | chore: bump version to 0.0.119 | ||
|
|
4eab641db1 |
Done! The runner has been fixed. Changed macos-13 to macos-15-intel for the x86_64-apple-darwin build, with a comment explaining this is the last Intel runner image. (#1326)
|
||
|
|
79a3d26278 |
Done. Bumped Amp from 0.0.1763179276-g784b75 to 0.0.1763482408-g51ddaa. (#1324)
|
||
|
|
fea5a1b7ce |
Done. Updated [gemini.rs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/8fc7-bump-gemini-to-n/crates/executors/src/executors/gemini.rs#L24) to use @google/gemini-cli@0.16.0. (#1323)
|
||
|
|
36bde0b4b9 |
Frontend file naming eslint rule (vibe-kanban) (#1322)
* Perfect! Now let me create a summary for you: ## ✅ ESLint Configuration Complete The linter has identified **29 files** that need to be renamed: ### **Files to Rename:** #### **Components → PascalCase (15 files)** ``` config-provider.tsx → ConfigProvider.tsx diff-view-switch.tsx → DiffViewSwitch.tsx logo.tsx → Logo.tsx navbar.tsx → Navbar.tsx (in layout/) search-bar.tsx → SearchBar.tsx theme-provider.tsx → ThemeProvider.tsx style-override.tsx → StyleOverride.tsx copy-files-field.tsx → CopyFilesField.tsx (in projects/) project-detail.tsx → ProjectDetail.tsx (in projects/) project-form-fields.tsx → ProjectFormFields.tsx (in projects/) project-list.tsx → ProjectList.tsx (in projects/) ``` #### **Contexts → PascalCase (2 files)** ``` project-context.tsx → ProjectContext.tsx search-context.tsx → SearchContext.tsx ``` #### **Pages → PascalCase (3 files)** ``` full-attempt-logs.tsx → FullAttemptLogs.tsx project-tasks.tsx → ProjectTasks.tsx projects.tsx → Projects.tsx ``` #### **Lib → camelCase (2 files)** ``` caret-position.ts → caretPosition.ts mcp-strategies.ts → mcpStrategies.ts ``` #### **Utils → camelCase (3 files)** ``` companion-install-task.ts → companionInstallTask.ts script-placeholders.ts → scriptPlaceholders.ts status-labels.ts → statusLabels.ts ``` #### **UI (shadcn) → kebab-case (4 files)** ``` ActionsDropdown.tsx → actions-dropdown.tsx ImageUploadSection.tsx → image-upload-section.tsx TitleDescriptionEditor.tsx → title-description-editor.tsx DataTable.tsx → data-table.tsx (in table/) Table.tsx → table.tsx (in table/) ImageChipNode.tsx → image-chip-node.tsx (in wysiwyg/) imageChipMarkdown.ts → image-chip-markdown.ts (in wysiwyg/) ``` #### **Entry Point (special case - 1 file)** ``` main.tsx → can stay as main.tsx (entry point convention) ``` **Next steps:** Should I proceed with renaming these files using `git mv`? * ## ✅ Complete! File Naming Standardization Successful ### **Summary** Successfully implemented and enforced file naming conventions for the frontend: ### **What Was Done:** 1. ✅ **Installed** `eslint-plugin-check-file@^2.8.0` 2. ✅ **Configured ESLint** with file naming rules: - **Components (.tsx)**: `PascalCase` - **Hooks (.ts)**: `camelCase` (with `use` prefix) - **Utils/Lib (.ts)**: `camelCase` - **Shadcn UI**: `kebab-case` (library convention) - **Entry points**: Excluded (`main.tsx`, `vite-env.d.ts`) 3. ✅ **Renamed 28 files** using `git mv`: - 10 components → PascalCase - 2 contexts → PascalCase - 3 pages → PascalCase - 2 lib files → camelCase - 3 utils → camelCase - 7 UI components → kebab-case - 1 utils component → PascalCase 4. ✅ **Fixed all imports** across the codebase (77 files modified) 5. ✅ **Verified**: - ✅ ESLint passes (no filename errors) - ✅ TypeScript check passes (no errors) - ✅ Build successful ### **Git Status:** - 28 files renamed (with history preserved via `git mv`) - 77 total files changed (renames + import updates) ### **Ready for commit!** The codebase now has consistent, enforceable file naming conventions that will prevent future inconsistencies. * Cleanup script changes for task attempt 11f8d7b9-99b5-41ce-934c-5ce75008a200 |
||
|
|
0bd36a3b3a |
disable eslint-disable comments (vibe-kanban) (#1321)
* Done! All eslint-disable comments are now banned and the codebase is clean. **Summary of changes:** 1. **Installed** `eslint-plugin-eslint-comments` 2. **Updated** [frontend/.eslintrc.cjs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/2550-disable-eslint-d/frontend/.eslintrc.cjs) to enforce the ban 3. **Fixed 3 files** by refactoring code instead of suppressing rules: - [FeatureShowcaseModal.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/2550-disable-eslint-d/frontend/src/components/showcase/FeatureShowcaseModal.tsx): Added ref to track activeScopes snapshot - [ShareDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/2550-disable-eslint-d/frontend/src/components/dialogs/tasks/ShareDialog.tsx): Added shareTask object to dependencies - [wysiwyg.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/2550-disable-eslint-d/frontend/src/components/ui/wysiwyg.tsx): Added didInit ref guard for run-once effect All checks pass ✓ * lint fix |
||
|
|
18ae6c5fd6 |
Refactor FeatureShowcaseModal to use lib/modals (vibe-kanban) (#1308)
* Perfect! All type checks pass. The refactoring is complete.
## Summary
Successfully refactored [FeatureShowcaseModal.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/components/showcase/FeatureShowcaseModal.tsx) to use the `lib/modals` pattern:
**Changes made:**
1. **FeatureShowcaseModal.tsx:**
- Wrapped component with `NiceModal.create<Props>()`
- Added `useModal()` hook to manage visibility
- Replaced `isOpen` prop → `modal.visible`
- Replaced `onClose()` → `modal.hide()`
- Added `onExitComplete` to AnimatePresence for proper cleanup
- Updated keyboard scope effect to restore scopes only on cleanup
- Exported via `defineModal<Props, void>()`
2. **project-tasks.tsx:**
- Removed JSX usage of `<FeatureShowcaseModal>`
- Added effect to call `FeatureShowcaseModal.show()` when trigger fires
- Properly handles cleanup with `.finally()` callback
All type checks pass ✓
* Cleanup script changes for task attempt dd42978a-2a1a-44bd-9e2e-aa0c6575d236
* Perfect! Refactoring complete.
## Summary
Successfully refactored FeatureShowcaseModal to use the `lib/modals` pattern:
**Files changed:**
1. **Moved & renamed:** `frontend/src/components/showcase/FeatureShowcaseModal.tsx` → [frontend/src/components/dialogs/global/FeatureShowcaseDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/components/dialogs/global/FeatureShowcaseDialog.tsx)
- Wrapped with `NiceModal.create<Props>()`
- Uses `useModal()` for visibility control
- Exports via `defineModal<Props, void>()`
- Updated keyboard scope management to restore on cleanup only
2. **Updated:** [frontend/src/pages/project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/pages/project-tasks.tsx)
- Removed JSX usage
- Calls `FeatureShowcaseDialog.show()` when trigger fires
- Properly handles cleanup with `.finally()` callback
All type checks and linting pass ✓
* Cleanup script changes for task attempt dd42978a-2a1a-44bd-9e2e-aa0c6575d236
* Refactor FeatureShowcaseDialog to use Dialog component (vibe-kanban 8a3e4ceb)
Use the Dialog component, like all the other dialogs/modals
* Perfect! Refactoring complete.
## Summary
Successfully eliminated the state-based trigger pattern by enhancing `useShowcaseTrigger` with a direct callback approach.
**Changes made:**
1. **[useShowcaseTrigger.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/hooks/useShowcaseTrigger.ts):**
- Added `onShow?: () => Promise<unknown>` to options
- Stored callback in ref to avoid stale closures
- Calls `onShow()` directly when conditions are met
- Automatically calls `close()` when promise resolves (marks as seen)
2. **[project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/pages/project-tasks.tsx):**
- Removed `useEffect` that watched `isOpen` state
- Removed manual `close()` call
- Passes `FeatureShowcaseDialog.show()` as `onShow` callback
- Reduced from 13 lines to 4 lines
**Result:** Clean, declarative API that matches the lib/modals imperative pattern. No more state to trigger side effects.
All type checks pass ✓
* Perfect! The persistence tracking is now fixed.
## Summary
Successfully fixed showcase persistence tracking by resolving the stale closure issue.
**Changes to [useShowcaseTrigger.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/hooks/useShowcaseTrigger.ts):**
1. **Destructured persistence** to get stable function references:
- `const { isLoaded, hasSeen, markSeen } = useShowcasePersistence()`
- Avoids object identity changes causing re-renders
2. **Moved `close` callback before the effect** that uses it:
- Now defined at line 60 (before the effect at line 74)
- Depends on stable references: `config.id`, `markSeenOnClose`, `markSeen`
3. **Added `close` to effect dependencies**:
- Updated dependency array: `[isLoaded, enabled, hasSeenState, openDelay, resetOnDisable, close]`
- Effect now stays in sync with the latest `close` function
4. **Updated all references** to use destructured values instead of `persistence.*`
**Result:** When the dialog closes, `markSeen(config.id)` is properly called and the showcase is persisted to config, preventing it from showing again.
All type checks pass ✓
* Perfect! Successfully eliminated the `useShowcaseTrigger` hook.
## Summary
Removed unnecessary abstraction layer by inlining showcase logic directly where it's used.
**Changes:**
1. **[project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/pages/project-tasks.tsx):**
- Replaced `useShowcaseTrigger` with direct `useShowcasePersistence` usage
- Added inline effect that:
- Checks if showcase has been seen
- Waits 300ms before showing (prevents flash during mount)
- Shows `FeatureShowcaseDialog` when panel opens for first time
- Marks as seen when dialog closes
- Properly cleans up timer with `cancelled` flag
- Much clearer: logic is visible at point of use
2. **Deleted:** `frontend/src/hooks/useShowcaseTrigger.ts` (no longer needed)
**Result:**
- **Simpler:** 20 lines of clear, inline logic vs. 127-line hook file
- **More readable:** No indirection - you can see exactly what happens when
- **Same behavior:** Persistence tracking, delay, proper cleanup all preserved
All type checks pass ✓
* Cleanup script changes for task attempt dd42978a-2a1a-44bd-9e2e-aa0c6575d236
* Perfect! Successfully eliminated the `useShowcasePersistence` hook.
Removed unnecessary abstraction by accessing config directly instead of through a dedicated hook.
**Changes:**
1. **[project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/pages/project-tasks.tsx):**
- Replaced `useShowcasePersistence()` with direct `useUserSystem()` call
- Direct access to `config`, `updateAndSaveConfig`, `loading`
- Inline computation of `seenFeatures` array and `seen` boolean
- Updated config directly in effect's finally block
- Added idempotent guard (`seenFeatures.includes(showcaseId)`) before saving
2. **Deleted:** `frontend/src/hooks/useShowcasePersistence.ts` (42 lines, unused)
**Result:**
- **Simpler:** No intermediate hook, direct config access
- **Clearer:** Can see exactly what config is being read/written
- **No unnecessary abstractions:** Removed `useCallback` wrappers that didn't stabilize anything
- **Same behavior:** Persistence tracking, idempotent writes, proper cleanup
All type checks pass ✓
Successfully refactored FeatureShowcaseModal to use lib/modals pattern and eliminated unnecessary abstractions:
1. ✅ Converted FeatureShowcaseModal → FeatureShowcaseDialog with NiceModal
2. ✅ Moved to dialogs/global/ directory
3. ✅ Fixed keyboard scope management
4. ✅ Eliminated state-based trigger pattern (removed useEffect watching isOpen)
5. ✅ Removed useShowcaseTrigger hook (127 lines → inline)
6. ✅ Removed useShowcasePersistence hook (42 lines → direct config access)
**Final state:** Clean, readable, direct implementation with no unnecessary abstractions.
* Cleanup script changes for task attempt dd42978a-2a1a-44bd-9e2e-aa0c6575d236
* Perfect! Removed the unnecessary timeout.
## Summary
Simplified the showcase effect by removing the 300ms delay.
**Change to [project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/pages/project-tasks.tsx):**
- Removed `setTimeout` wrapper and 300ms delay
- Removed timer cleanup from return statement
- Kept `cancelled` flag to prevent config update after unmount
- Dialog now shows immediately when conditions are met
**Result:** Simpler, more direct code - showcase appears immediately when panel opens for the first time.
All type checks pass ✓
* Cleanup script changes for task attempt dd42978a-2a1a-44bd-9e2e-aa0c6575d236
* Perfect! The showcase logic is now extremely clean and simple.
## Summary
Removed the unnecessary `cancelled` flag from the showcase effect.
**Change to [project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/dd42-refactor-feature/frontend/src/pages/project-tasks.tsx):**
- Removed `cancelled` flag and cleanup function
- `updateAndSaveConfig` is safe to call after unmount (just updates config/calls API)
- Idempotent guard (`seenFeatures.includes(showcaseId)`) prevents duplicate saves
**Final showcase implementation (10 lines):**
```tsx
useEffect(() => {
if (!isLoaded || !isPanelOpen || seen) return;
FeatureShowcaseDialog.show({ config: showcases.taskPanel }).finally(() => {
if (seenFeatures.includes(showcaseId)) return;
void updateAndSaveConfig({
showcases: { seen_features: [...seenFeatures, showcaseId] },
});
});
}, [isLoaded, isPanelOpen, seen, showcaseId, updateAndSaveConfig, seenFeatures]);
```
All type checks pass ✓
## Complete Refactoring Results
Transformed the feature showcase system from complex abstractions to simple, direct code:
- ✅ Converted to lib/modals pattern (NiceModal)
- ✅ Eliminated 2 unnecessary hooks (169 lines removed)
- ✅ Removed unnecessary timeout and cancellation logic
- ✅ Final result: **10 lines of clear, direct code** that shows dialog and saves config
* Cleanup script changes for task attempt dd42978a-2a1a-44bd-9e2e-aa0c6575d236
* hide and save properly
|
||
|
|
81b92c6ec3 |
Resolve frontend warnings final (#1319)
* ## ✅ Complete - First 3 Categories Fixed Successfully resolved **13 of 26 TypeScript warnings** (50% reduction): ### **Changes Made:** **Category 1: Intl Polyfill (1 warning fixed)** - [TaskPanel.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/components/panels/TaskPanel.tsx#L39-L42): Replaced `(Intl as any).RelativeTimeFormat` with proper feature detection **Category 2: Lexical Transformers (5 warnings fixed)** - [wysiwyg.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/components/ui/wysiwyg.tsx): Imported `Transformer` type and typed all arrays/props - [ImageChipNode.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/components/ui/wysiwyg/ImageChipNode.tsx): Used `unknown` with type assertion for `importJSON` **Category 3: MCP Config JSON (7 warnings fixed)** - [mcp-strategies.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/lib/mcp-strategies.ts): - Added `JsonObject` type and `isJsonObject` guard using existing `JsonValue` from shared/types - Updated all 4 methods with proper types and runtime guards - Fixed edge case for empty `servers_path` in `addPreconfiguredToConfig` ### **Verification:** - ✅ `pnpm run lint` - Warnings reduced from 26 → 13 - ✅ `pnpm run check` - TypeScript compilation passes - ✅ Rust backend lint passes ### **Remaining Warnings (13):** - GitOperations.tsx: 3 warnings (branch merge parsing) - ClickedElementsBanner.tsx: 1 warning - useFollowUpSend.ts: 1 warning - usePinnedTodos.ts: 1 warning - useTaskMutations.ts: 2 warnings - project-tasks.tsx: 3 warnings - AgentSettings.tsx: 2 warnings * Excellent! All warnings are resolved. Let me create a summary: ## ✅ Complete - Categories 4-6 Fixed (All 26 warnings resolved!) Successfully resolved **all 26 TypeScript warnings** (100% completion): ### **Category 4: Git Merge Data** (3 warnings fixed) - [GitOperations.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/components/tasks/Toolbar/GitOperations.tsx): Imported `Merge` type from shared/types and properly typed merge filtering/finding operations ### **Category 5: Error Handlers** (5 warnings fixed) - [useFollowUpSend.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/hooks/follow-up/useFollowUpSend.ts): Used `CreateFollowUpAttempt` type for API request body - [usePinnedTodos.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/hooks/usePinnedTodos.ts): Used `NormalizedEntry` type from shared/types - [useTaskMutations.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/hooks/useTaskMutations.ts): Removed unnecessary casts (parent_task_attempt exists on TaskWithAttemptStatus) - [ClickedElementsBanner.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/components/tasks/ClickedElementsBanner.tsx): Defined `ComponentInfo` type derived from ClickedEntry ### **Category 6: Settings Page** (2 warnings fixed) - [AgentSettings.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/pages/settings/AgentSettings.tsx): - Defined `ProfilesDoc` type for parsed profiles structure - Changed `selectedExecutorType` from `string` to `BaseCodingAgent` enum ### **Additional Fixes:** - [project-tasks.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/pages/project-tasks.tsx): Added proper types for DiffsPanelContainer props (TaskAttempt, BranchStatus) ### **Verification:** - ✅ `pnpm run lint` - **0 warnings** (reduced from 26) - ✅ `pnpm run check` - TypeScript compilation passes - ✅ Rust backend lint passes **All frontend TypeScript warnings have been eliminated while maintaining code readability and type safety!** * ## ✅ Complete - ExecutorConfigs Added as Shared Type Successfully replaced the local `ProfilesDoc` type with the backend-generated `ExecutorConfigs` type. ### **Changes Made:** **Backend:** - [generate_types.rs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/crates/server/src/bin/generate_types.rs#L108): Added `ExecutorConfigs` to exported types - [shared/types.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/shared/types.ts#L225): Generated new `ExecutorConfigs` type **Frontend:** - [AgentSettings.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/pages/settings/AgentSettings.tsx): - Removed local `ProfilesDoc` type - Imported and used `ExecutorConfigs` from shared/types - Added `ExecutorsMap` helper type for accessing the nested structure with string keys - Used `as unknown as ExecutorsMap` to safely access dynamic executor configurations ### **Benefits:** - ✅ Single source of truth between frontend and backend - ✅ Frontend shape matches backend contract exactly - ✅ Better maintainability - type changes sync automatically - ✅ More explicit about what the profiles structure represents ### **Verification:** - ✅ `pnpm run check` - TypeScript compilation passes - ✅ `pnpm run lint` - **0 warnings** (all 26 warnings resolved) - ✅ Rust backend lint/check passes **All frontend warnings have been resolved and ProfilesDoc is now properly typed using the backend-generated ExecutorConfigs type!** * Cleanup script changes for task attempt 3bbe8d2c-14b3-43eb-af98-abbc74f60742 * ## ✅ Complete - JSON Handling Improved Successfully improved JSON handling in mcp-strategies.ts with a simple, idiomatic change: ### **Change Made:** [mcp-strategies.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3bbe-resolve-frontend/frontend/src/lib/mcp-strategies.ts#L3): ```typescript // Before: type JsonObject = { [key: string]: JsonValue }; // After: type JsonObject = Record<string, JsonValue>; ``` ### **Oracle's Analysis:** - ✅ **Keep it local** - Only this file needs it, no need for shared utilities - ✅ **Keep the type guard** - Essential for runtime safety when parsing/traversing JSON - ✅ **Use Record** - More idiomatic TypeScript than index signature - ❌ **No backend export needed** - Would add unnecessary complexity - ❌ **No shared file needed** - Single-use type doesn't warrant it ### **Verification:** - ✅ `pnpm run check` - TypeScript compilation passes - ✅ `pnpm run lint` - **0 warnings** - ✅ Rust backend passes **The local JSON handling approach is the simplest and most readable solution for this use case!** |
||
|
|
b04672d776 |
CMD+shift+enter should create task without start (vibe-kanban) (#1317)
* Done! CMD+Shift+Enter will now create tasks without starting them. **Changes made:** 1. Added `useKeySubmitTaskAlt` import 2. Added `forceCreateOnlyRef` to track create-only mode 3. Updated validator to skip executor/branch requirements when ref is true 4. Updated submit logic to check `autoStart && !forceCreateOnlyRef.current` 5. Added `handleSubmitCreateOnly` callback that sets ref, submits, and cleans up 6. Bound CMD+Shift+Enter with simpler validation (just needs title) All type checks pass ✓ * Cleanup script changes for task attempt 2eb2be96-3b6c-4471-9964-3cff2dc9feef |
||
|
|
1dae217f1a |
Resolve frontend warnings (vibe-kanban) (#1316)
* ## ✅ Batch 1 Complete Successfully fixed all 6 warnings in batch 1 (message boundaries & streams): ### Changes made: **[bridge.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/19c9-resolve-frontend/frontend/src/vscode/bridge.ts)** - 5 fixes: - Replaced `(window as any).InputEvent` checks with `typeof InputEvent === 'function'` - Removed unnecessary type assertions on `dispatchEvent` calls - More readable runtime guards using built-in DOM types **[useJsonPatchWsStream.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/19c9-resolve-frontend/frontend/src/hooks/useJsonPatchWsStream.ts)** - 1 fix: - Added eslint suppression with explanation for `rfc6902` library requirement **[frontend/package.json](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/19c9-resolve-frontend/frontend/package.json)**: - Reduced `max-warnings` from 110 → 30 to lock in progress ### Results: - **Before:** 32 warnings - **After:** 26 warnings - **Eliminated:** 6 warnings from batch 1 - **Remaining batches:** 2-6 (26 warnings) * Perfect! ✅ The solution works without any `eslint-disable` comments. ## What we changed: 1. **Added type constraint**: `<T extends object>` - documents that JSON Patch only works on objects/arrays 2. **Used local variable narrowing**: `const current = dataRef.current` narrows `T | undefined` to `T` 3. **Removed the cast**: `applyPatch(next, filtered)` works directly since `applyPatch` already accepts `any` 4. **Cleaner code flow**: `const next = structuredClone(current)` then update refs The code is now more readable, type-safe (within TypeScript's limits for this library), and passes both lint and typecheck with **no suppressions needed**. |
||
|
|
9d8c0b286f |
Perfect! I've fixed the hook invalidation issue. (#1309)
The problem was that after rebasing, the `useRebase` hook wasn't invalidating the `taskAttempt` query, so the Create PR dialog would read stale `target_branch` data from the cache. I added the missing invalidation at `frontend/src/hooks/useRebase.ts:43-46`, matching the pattern already used correctly in `useChangeTargetBranch.ts`. Now when a user rebases via the UI, the task attempt query will be invalidated and the Create PR dialog will show the updated target/base branch. |
||
|
|
b35708e7b9 |
## ✅ Batch D Complete (#1313)
Successfully fixed all low-priority `any` types and catch blocks across 7 files: ### Changes Made: **1. [lib/types.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/lib/types.ts)** - Added imports: `NormalizedEntry`, `ExecutionProcessStatus` - `entry: any` → `entry: NormalizedEntry` - `process: any` → `process: ExecutionProcess` - `processStatus: string` → `processStatus: ExecutionProcessStatus` **2. [lib/modals.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/lib/modals.ts)** - Removed `any[]` and `component as any` - Properly typed function arguments with `ShowArgs<P>` - Used `React.FC<ComponentProps<P>>` for NiceModal compatibility **3. [EditBranchNameDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/dialogs/tasks/EditBranchNameDialog.tsx)** - `catch (err: any)` → `catch (err: unknown)` - Used `getErrorMessage(err)` helper **4. [TagEditDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/dialogs/tasks/TagEditDialog.tsx)** - `catch (err: any)` → `catch (err: unknown)` - Used `getErrorMessage(err)` helper **5. [GhCliSetupDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/dialogs/auth/GhCliSetupDialog.tsx)** - `catch (err: any)` → `catch (err: unknown)` - Added safe type narrowing with `isGhCliSetupError` guard - Used `getErrorMessage(err)` helper **6. [ImageUploadSection.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/components/ui/ImageUploadSection.tsx)** - `catch (error: any)` → `catch (error: unknown)` - Used `instanceof Error` check **7. [McpSettings.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3da6-batch-d-fix-low/frontend/src/pages/settings/McpSettings.tsx)** - `catch (err: any)` → `catch (err: unknown)` - `Record<string, any>` → `Record<string, unknown>` for preconfigured/meta/servers - Added safe narrowing for meta access All type checks pass ✓ All formatting complete ✓ |
||
|
|
41376eba94 |
Batch C: Fix medium-priority 'any' in UI components (vibe-kanban) (#1312)
* ## ✅ Batch C Complete All medium-priority TypeScript `any` types have been fixed across 7 files: 1. **[markdown-renderer.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/ui/markdown-renderer.tsx)** - Replaced 11 `any` with `React.ComponentProps<'tag'>` 2. **[ExecutorConfigForm.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/ExecutorConfigForm.tsx)** - Used `unknown` for form data, `IChangeEvent<unknown>` for handlers 3. **[FormTemplate.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/rjsf/templates/FormTemplate.tsx)** - Replaced with `React.PropsWithChildren` 4. **[ArrayFieldTemplate.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/rjsf/templates/ArrayFieldTemplate.tsx)** - Created minimal `ArrayItemWithButtons` type for RJSF v6 beta 5. **[DiffsPanel.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/panels/DiffsPanel.tsx)** - Used `Diff[]` and typed `t` function properly 6. **[DiffCard.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/DiffCard.tsx)** - Used existing `ReviewComment` type from context 7. **[useGitOperations.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/hooks/useGitOperations.ts)** - Properly narrowed `unknown` errors with type guards `pnpm run check` passes ✅ * Cleanup script changes for task attempt 5fe86537-3bc1-4d78-96c0-95347fc7c05f * Excellent! The build succeeds. Now let's create a summary: ## ✅ Batch C Complete + RJSF Upgrade Successfully fixed all medium-priority TypeScript `any` types **and** upgraded RJSF to stable 6.1.1: ### Type Fixes (7 files) 1. **[markdown-renderer.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/ui/markdown-renderer.tsx)** - Replaced 11 `any` with `React.ComponentProps<'tag'>` 2. **[ExecutorConfigForm.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/ExecutorConfigForm.tsx)** - Used `unknown` and `IChangeEvent<unknown>` 3. **[FormTemplate.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/rjsf/templates/FormTemplate.tsx)** - Used `React.PropsWithChildren` 4. **[ArrayFieldTemplate.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/rjsf/templates/ArrayFieldTemplate.tsx)** - Migrated to stable RJSF v6 API with `ArrayFieldItemTemplate` 5. **[DiffsPanel.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/panels/DiffsPanel.tsx)** - Used `Diff[]` and proper `t` function type 6. **[DiffCard.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/components/DiffCard.tsx)** - Used `ReviewComment` type from context 7. **[useGitOperations.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5fe8-batch-c-fix-medi/frontend/src/hooks/useGitOperations.ts)** - Properly narrowed `unknown` with type guards ### Dependency Upgrades - `@rjsf/core`: 6.0.0-beta.11 → **6.1.1** (stable) - `@rjsf/utils`: 6.0.0-beta.11 → **6.1.1** (stable) - `@rjsf/validator-ajv8`: 6.0.0-beta.11 → **6.1.1** (stable) - `@rjsf/shadcn`: 6.0.0-beta.10 → **6.1.1** (stable) ### RJSF Migration Updated to v6 stable API: - Removed workaround type (no longer needed) - Added `ArrayFieldItemTemplate` for proper item rendering - Updated to use `onRemoveItem` callback instead of deprecated `onDropIndexClick` All checks pass ✅ * Cleanup script changes for task attempt 5fe86537-3bc1-4d78-96c0-95347fc7c05f |
||
|
|
870a166c38 |
Batch A: Fix high-priority 'any' types in core files (vibe-kanban) (#1310)
* Perfect! All type checks pass. Here's a summary of the completed fixes: ## ✅ Batch A Complete: Fixed all 'any' types in 7 core files ### Summary of Changes **1. useLogStream.ts** - Typed WebSocket patches - `patches.forEach((patch: any)` → `const patches = data.JsonPatch as Array<{ value?: PatchType }>` **2. api.ts** - Typed request body - `const requestBody: any = {}` → `const requestBody: { editor_type?: EditorType } = {}` **3. NextActionCard.tsx** - Used proper domain type - `task?: any` → `task?: TaskWithAttemptStatus` **4. PendingApprovalEntry.tsx** - Safe error handling - `catch (e: any)` → `catch (e: unknown)` with proper narrowing **5. useProfiles.ts** - Typed JSON values - `parsedProfiles: any | null` → `parsedProfiles: JsonValue | null` - `queryClient.setQueryData(['profiles'], (old: any)` → typed with `<{ content: string; path: string }>` **6. useProcessRetry.ts** - Typed executor actions - `const typ: any = details?.executor_action?.typ as any` → `const typ: ExecutorActionType | undefined` - Removed unnecessary `as any` cast on version field **7. DisplayConversationEntry.tsx** - Created ActionLike helper type - Removed local `type JsonValue = any` - Imported `JsonValue` and `TaskWithAttemptStatus` from shared/types - Created minimal `ActionLike` type for ToolCallCard compatibility - Typed all component props and variables properly All changes passed frontend and backend type checks ✓ * Cleanup script changes for task attempt 1b9207c2-6291-4bea-b06d-b4702f99f9ee * Perfect! Updated the `ActionLike` type to use `CommandRunResult` from shared types, which is cleaner and more aligned with the domain model. All type checks pass ✓ * Excellent! All checks pass. Let me create a summary of what we accomplished: ## ✅ Refactor Complete: Simplified ToolCallCard by Passing Full Entry ### Summary of Changes **Removed the ActionLike workaround** and made the code significantly simpler and more readable: ### Before (Complex with ActionLike bridge): ```typescript // Helper type to bridge ExecutorAction and ActionType type ActionLike = Partial<{ action: string; arguments: JsonValue; result: CommandRunResult; tool_name: string; message: string; summary: string; }>; // Multiple props with conversions at call sites <ToolCallCard entryType={toolEntry} entryContent={entry.content} defaultExpanded={defaultExpanded} statusAppearance={statusAppearance} forceExpanded={isPendingApproval} linkifyUrls={isGithubCliSetup} /> ``` ### After (Simple with unified entry): ```typescript // Just pass the entry - ToolCallCard handles everything <ToolCallCard entry={entry} expansionKey={expansionKey} forceExpanded={isPendingApproval} /> ``` ### Key Improvements 1. **Simpler Props**: Changed from 8+ props to just 3 (`entry`, `expansionKey`, `forceExpanded`) 2. **Removed ActionLike**: Eliminated the bridge type that was papering over type differences 3. **Centralized Logic**: All normalization logic now lives inside ToolCallCard where it belongs 4. **Type Safety**: Uses proper type narrowing (`'entry_type' in entry`) instead of type casts 5. **Better Readability**: Call sites are now trivial - just pass the entry ### Files Changed - `DisplayConversationEntry.tsx`: - Removed ActionLike helper type - Updated ToolCallCard component to accept unified entry prop - Simplified both call sites (ProcessStartPayload and NormalizedEntry) - Moved linkifyUrls, defaultExpanded logic into ToolCallCard All type checks pass ✓ * Cleanup script changes for task attempt 1b9207c2-6291-4bea-b06d-b4702f99f9ee |
||
|
|
5e7742da2a |
Batch B: Fix React Hooks dependency warnings in core files (vibe-kanban) (#1307)
* Excellent! All done! Let me create a summary: ## ✅ Batch B Complete: All React Hooks Exhaustive-Deps Warnings Fixed Successfully fixed **all 22 exhaustive-deps warnings** across the codebase. The changes improved code correctness and stability. ### Files Fixed (15 total): 1. **useProjectTasks.ts** - Wrapped logical expressions in useMemo 2. **useConversationHistory.ts** - Wrapped functions in useCallback, added missing deps 3. **useShowcasePersistence.ts** - Wrapped logical expression in useMemo 4. **auto-expanding-textarea.tsx** - Added missing deps, destructured props 5. **App.tsx** - Added missing updateAndSaveConfig dep 6. **EditDiffRenderer.tsx** - Removed unnecessary path dep 7. **PreviewPanel.tsx** - Fixed latestDevServerProcess dependency 8. **project-form-fields.tsx** - Wrapped loadRecentRepos in useCallback 9. **project-list.tsx** - Wrapped fetchProjects in useCallback 10. **ImageUploadSection.tsx** - Added isExpanded dep 11. **file-search-textarea.tsx** - Added textareaRef dep 12. **useJsonPatchWsStream.ts** - Fixed options dependency 13. **useSemanticKey.ts** - Removed unnecessary action dep 14. **McpSettings.tsx** - Added profiles dep 15. **project-tasks.tsx** - Moved navigateWithSearch before usage ### Key Changes: - Added `useCallback` where functions are used in dependency arrays - Added `useMemo` to stabilize object/array references - Fixed function declaration order to avoid hoisting issues - One ESLint disable for circular dependency case (documented) ### Verification: - ✅ **0 exhaustive-deps warnings** (down from 22) - ✅ **Type check passes** (`pnpm run check`) - ✅ **All changes follow style guide** (simplest, most readable) * Cleanup script changes for task attempt 0564411a-2cf4-488a-a082-d0f7ebcfc101 * Perfect! All fixed. Let me create a summary: ## ✅ Fixed Infinite Re-render Issue in useJsonPatchWsStream ### Root Cause The `options` object had a new identity on every render (from default `= {}`), causing the useEffect to restart infinitely and trigger continuous re-renders. ### Changes Applied **useJsonPatchWsStream.ts:** 1. ✅ Removed default parameter: `options?: UseJsonPatchStreamOptions<T>` (no more `= {}`) 2. ✅ Destructured options at the top: ```typescript const injectInitialEntry = options?.injectInitialEntry; const deduplicatePatches = options?.deduplicatePatches; ``` 3. ✅ Updated all usages to use destructured variables 4. ✅ Fixed dependency array: ```typescript }, [endpoint, enabled, initialData, injectInitialEntry, deduplicatePatches, retryNonce]); ``` **useConversationHistory.ts:** - Added comment explaining why `emitEntries` is omitted from deps (it's stable) ### Verification - ✅ **Type check passes** (`pnpm run check`) - ✅ **0 exhaustive-deps warnings** - ✅ **No infinite re-renders** (destructured variables have stable identities) ### Why This Works - Destructured variables (`injectInitialEntry`, `deduplicatePatches`) maintain stable identities across renders (undefined stays undefined) - Only changes when callbacks are actually different, not on every render - More explicit and readable - shows exactly what triggers reconnection * Cleanup script changes for task attempt 0564411a-2cf4-488a-a082-d0f7ebcfc101 * Perfect! Let me create a final summary of all the work done: ## ✅ Complete: Removed eslint-disable Tech Debt ### What Was Done Refactored `useConversationHistory.ts` to eliminate the eslint-disable by reordering function definitions so dependencies are declared before use. ### Changes **Reordered functions in useConversationHistory.ts:** ``` Old order: loadRunningAndEmit → emitEntries (hoisting error) New order: 1. patchWithKey (helper) 2. flattenEntries (helper) 3. getActiveAgentProcess (helper) 4. flattenEntriesForEmit (useCallback) 5. emitEntries (useCallback, depends on flattenEntriesForEmit) ✅ 6. loadRunningAndEmit (useCallback, depends on emitEntries) ✅ 7. loadRunningAndEmitWithBackoff (depends on loadRunningAndEmit) ``` **Updated dependency array:** - `loadRunningAndEmit`: Now properly includes `[emitEntries]` - Removed eslint-disable comment ### Final Results - ✅ **0 exhaustive-deps warnings** (down from 22) - ✅ **TypeScript check passes** - ✅ **No eslint-disable tech debt** - ✅ **No infinite re-renders** - ✅ **More readable** (dependencies declared before use) All React Hooks warnings properly fixed with clean, maintainable code! * Cleanup script changes for task attempt 0564411a-2cf4-488a-a082-d0f7ebcfc101 |
||
|
|
aaaeccf2a3 | chore: bump version to 0.0.118 | ||
|
|
aab01cb705 |
Add we're hiring to the readme (vibe-kanban) (#1306)
* Done! Added the hiring link below the badges in [README.md](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/5d37-add-we-re-hiring/README.md#L17-L19). * h1 |
||
|
|
11f0bf7e3d |
MCP context (vibe-kanban) (#1185)
* **MCP Context Wiring** - Added a reusable context payload and env constant so every attempt can describe itself as JSON (`crates/utils/src/vk_mcp_context.rs:1`). - Threaded that payload through executor launches via a new `ExecutorRuntimeContext`, pushing `VK_MCP_CONTEXT_JSON` into each agent process (e.g. `crates/executors/src/actions/mod.rs:20`, `crates/executors/src/executors/claude.rs:158`, `crates/executors/src/executors/acp/harness.rs:60`). - When an attempt starts we now build the context blob from project/task/attempt metadata and pass it to every execution (initial, follow-up, cleanup) (`crates/local-deployment/src/container.rs:823`). - The MCP task server reads the env, keeps the parsed struct, and only exposes a new `get_vk_context` tool when the blob is present; instructions call it out conditionally (`crates/server/src/mcp/task_server.rs:240`, `crates/server/src/mcp/task_server.rs:397`, `crates/server/src/mcp/task_server.rs:622`). Tests: `cargo check` You may want to sanity-test an executor path (e.g., start a Claude attempt and invoke `get_vk_context`) to see the live payload returned. - Kept the prompt plumbing lean: `ExecutorRuntimeContext` is now just an optional JSON string, and coding actions hand it to each agent via the new `use_runtime_context` hook instead of changing every `spawn` signature (`crates/executors/src/actions/mod.rs:20`, `crates/executors/src/actions/coding_agent_initial.rs:33`). - Each coding executor caches that string and injects `VK_MCP_CONTEXT_JSON` when it actually builds the `Command`, so only MCP-aware runs see the env; the harness got a light touch so Gemini/Qwen can pass the optional blob too (`crates/executors/src/executors/claude.rs:188`, `crates/executors/src/executors/amp.rs:36`, `crates/executors/src/executors/acp/harness.rs:46`). - Container still assembles the per-attempt metadata, but now it just builds the JSON once and hands it along; the MCP server logic from before remains untouched. Tests: `cargo check` If you want to test end-to-end, spin up an attempt with the VK MCP server enabled and call the new `get_vk_context` tool—you should see the env-driven payload without any prompt changes. - Trimmed MCP context payload to only the essentials: just project id/name, task id/title, attempt id/branch/target branch, plus execution id and executor (`crates/utils/src/vk_mcp_context.rs:9`, `crates/local-deployment/src/container.rs:832`). - Dropped the fields you called out (repo path, description, status, worktree path, backend URL) so agents can’t wander outside the worktree or get flooded with long text (`crates/local-deployment/src/container.rs:834`). - Ran `cargo fmt` and `cargo check` to confirm the lighter struct compiles cleanly. All cleaned up—let me know if you want any other context tweaks. - Trimmed the MCP payload helpers to the bare minimum and added a simple `VkMcpContext::new` constructor for building the JSON without extra wrappers (`crates/utils/src/vk_mcp_context.rs:1`). - Local container now invokes that constructor and serializes directly with `serde_json::to_string`, no stray repo paths/status/URLs left (`crates/local-deployment/src/container.rs:836`). - MCP server reads the env blob with `serde_json::from_str`, avoiding the removed helper (`crates/server/src/mcp/task_server.rs:249`). `cargo check` You’re set to retest—context only contains the trimmed fields, and the code paths compile clean. - Simplified the MCP context to only include project/task/attempt IDs and branch info, with a single `VkMcpContext::new` helper (`crates/utils/src/vk_mcp_context.rs:7`). - Container now builds the context directly from the execution/task data without extra lookups or name fields, then serializes via `serde_json::to_string` (`crates/local-deployment/src/container.rs:826`). - MCP server reuses `serde_json::from_str` to hydrate the env payload—no custom helpers needed (`crates/server/src/mcp/task_server.rs:250`). `cargo check` All review notes addressed; context stays minimal and derived straight from the execution context. - Context constructor now takes everything from the `ExecutionContext` itself—no extra project fetch or manual process ID threading—so we pass `execution_ctx.execution_process.id` (`crates/local-deployment/src/container.rs:826`). - `VkMcpContext::new` remains the lightweight helper; no other fields changed. - `cargo check` still green. That should satisfy the review comment; let me know if you want the helper to move inside `ExecutionContext` itself later. You’re right to call this out. The problem is that I kept reconstructing the MCP payload by pulling individual fields out of `execution_ctx` instead of passing the whole context through a helper. That meant I was effectively duplicating the same data extraction in several spots, which is exactly what you asked me to avoid. Even after I added `VkMcpContext::new`, I was still feeding it a pile of individual values and even chasing the project row myself. The fix is straightforward: provide a helper that takes the database `ExecutionContext` (already returned by `ExecutionProcess::load_context`) and use that directly. I’ve added `VkMcpContext::from_execution(&execution_ctx)` and switched the container to call it, so we call `serde_json::to_string(VkMcpContext::from_execution(&execution_ctx))`. No extra project lookups, no manual argument lists, and the helper itself is exactly where you expect it. Let me know if you want to drop the old `new(...)` constructor now that the context-based helper exists. Simplify rebase fixes * **MCP Context Wiring** - Added a reusable context payload and env constant so every attempt can describe itself as JSON (`crates/utils/src/vk_mcp_context.rs:1`). - Threaded that payload through executor launches via a new `ExecutorRuntimeContext`, pushing `VK_MCP_CONTEXT_JSON` into each agent process (e.g. `crates/executors/src/actions/mod.rs:20`, `crates/executors/src/executors/claude.rs:158`, `crates/executors/src/executors/acp/harness.rs:60`). - When an attempt starts we now build the context blob from project/task/attempt metadata and pass it to every execution (initial, follow-up, cleanup) (`crates/local-deployment/src/container.rs:823`). - The MCP task server reads the env, keeps the parsed struct, and only exposes a new `get_vk_context` tool when the blob is present; instructions call it out conditionally (`crates/server/src/mcp/task_server.rs:240`, `crates/server/src/mcp/task_server.rs:397`, `crates/server/src/mcp/task_server.rs:622`). Tests: `cargo check` You may want to sanity-test an executor path (e.g., start a Claude attempt and invoke `get_vk_context`) to see the live payload returned. - Kept the prompt plumbing lean: `ExecutorRuntimeContext` is now just an optional JSON string, and coding actions hand it to each agent via the new `use_runtime_context` hook instead of changing every `spawn` signature (`crates/executors/src/actions/mod.rs:20`, `crates/executors/src/actions/coding_agent_initial.rs:33`). - Each coding executor caches that string and injects `VK_MCP_CONTEXT_JSON` when it actually builds the `Command`, so only MCP-aware runs see the env; the harness got a light touch so Gemini/Qwen can pass the optional blob too (`crates/executors/src/executors/claude.rs:188`, `crates/executors/src/executors/amp.rs:36`, `crates/executors/src/executors/acp/harness.rs:46`). - Container still assembles the per-attempt metadata, but now it just builds the JSON once and hands it along; the MCP server logic from before remains untouched. Tests: `cargo check` If you want to test end-to-end, spin up an attempt with the VK MCP server enabled and call the new `get_vk_context` tool—you should see the env-driven payload without any prompt changes. - Trimmed MCP context payload to only the essentials: just project id/name, task id/title, attempt id/branch/target branch, plus execution id and executor (`crates/utils/src/vk_mcp_context.rs:9`, `crates/local-deployment/src/container.rs:832`). - Dropped the fields you called out (repo path, description, status, worktree path, backend URL) so agents can’t wander outside the worktree or get flooded with long text (`crates/local-deployment/src/container.rs:834`). - Ran `cargo fmt` and `cargo check` to confirm the lighter struct compiles cleanly. All cleaned up—let me know if you want any other context tweaks. - Trimmed the MCP payload helpers to the bare minimum and added a simple `VkMcpContext::new` constructor for building the JSON without extra wrappers (`crates/utils/src/vk_mcp_context.rs:1`). - Local container now invokes that constructor and serializes directly with `serde_json::to_string`, no stray repo paths/status/URLs left (`crates/local-deployment/src/container.rs:836`). - MCP server reads the env blob with `serde_json::from_str`, avoiding the removed helper (`crates/server/src/mcp/task_server.rs:249`). `cargo check` You’re set to retest—context only contains the trimmed fields, and the code paths compile clean. - Simplified the MCP context to only include project/task/attempt IDs and branch info, with a single `VkMcpContext::new` helper (`crates/utils/src/vk_mcp_context.rs:7`). - Container now builds the context directly from the execution/task data without extra lookups or name fields, then serializes via `serde_json::to_string` (`crates/local-deployment/src/container.rs:826`). - MCP server reuses `serde_json::from_str` to hydrate the env payload—no custom helpers needed (`crates/server/src/mcp/task_server.rs:250`). `cargo check` All review notes addressed; context stays minimal and derived straight from the execution context. - Context constructor now takes everything from the `ExecutionContext` itself—no extra project fetch or manual process ID threading—so we pass `execution_ctx.execution_process.id` (`crates/local-deployment/src/container.rs:826`). - `VkMcpContext::new` remains the lightweight helper; no other fields changed. - `cargo check` still green. That should satisfy the review comment; let me know if you want the helper to move inside `ExecutionContext` itself later. You’re right to call this out. The problem is that I kept reconstructing the MCP payload by pulling individual fields out of `execution_ctx` instead of passing the whole context through a helper. That meant I was effectively duplicating the same data extraction in several spots, which is exactly what you asked me to avoid. Even after I added `VkMcpContext::new`, I was still feeding it a pile of individual values and even chasing the project row myself. The fix is straightforward: provide a helper that takes the database `ExecutionContext` (already returned by `ExecutionProcess::load_context`) and use that directly. I’ve added `VkMcpContext::from_execution(&execution_ctx)` and switched the container to call it, so we call `serde_json::to_string(VkMcpContext::from_execution(&execution_ctx))`. No extra project lookups, no manual argument lists, and the helper itself is exactly where you expect it. Let me know if you want to drop the old `new(...)` constructor now that the context-based helper exists. Simplify rebase fixes * add VK_MCP_CONTEXT_JSON env var to MCP config * Version with vk context endpoint (vibe-kanban aa3bbf5f) In the last few commits we added the vk mcp context. I wanna refactor it to instead be an endpoint on normal vibe kanban, .../context, it takes a path in the body. It then uses a mehtod simialar to what's used for cleanup_orphaned_worktrees in crates/local-deployment/src/container.rs We don't inject context using env anymore. If the path is without vk context the mcp should return that info, too * Revert "add VK_MCP_CONTEXT_JSON env var to MCP config" This reverts commit c26ff986fc3533d63d4309b956b6d16f0fb0fa5b. * Revert "**MCP Context Wiring**" This reverts commit 62fc206dc79543fcee7895e2587eb790f019ddbb. * Revert "**MCP Context Wiring**" This reverts commit 0e988c859036124f0ccb5aef578c83b12b708e1a. * Move ctx endpoint to container * Prompts * Cleanup * Fetch context on init * surface error * comments * Rename to context |
||
|
|
a2df2334d0 |
Typesafe dialogs (vibe-kanban) (#1304)
* Excellent! ✅ All tasks completed successfully. Let me create a summary document: ## ✅ Typesafe Dialogs Refactoring Complete ### What Was Changed **1. New Typesafe Modal System** ([lib/modals.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/e9a3-typesafe-dialogs/frontend/src/lib/modals.ts)) - Created `defineModal<ResultType>(component)` to brand dialogs with return types - Created `showModal(modal, props)` with full type inference for props and return values - Added typed `hideModal()` and `removeModal()` helpers **2. Modals Registry** ([components/dialogs/index.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/e9a3-typesafe-dialogs/frontend/src/components/dialogs/index.ts)) - Exported `Modals` object with all 27 dialogs - Each modal properly typed with its result type - Autocomplete available via `Modals.*` **3. ESLint Enforcement** ([frontend/.eslintrc.cjs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/e9a3-typesafe-dialogs/frontend/.eslintrc.cjs)) - Blocks direct `NiceModal.show()` usage - Blocks `NiceModal.register()` usage - Restricts `NiceModal` imports to lib/modals.ts, App.tsx, and dialog files **4. Removed String Registrations** ([main.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/e9a3-typesafe-dialogs/frontend/src/main.tsx)) - Deleted 27 `NiceModal.register('string-id', Component)` calls - Dialogs now register automatically when used **5. Migrated All Call Sites** (14+ files) - Replaced `NiceModal.show('string-id', props)` → `showModal(Modals.X, props)` - All props and return types now fully typed - Legacy helper functions maintained for backward compatibility ### Usage Examples ```typescript // Before (not type-safe): const result = await NiceModal.show('onboarding'); // ❌ No autocomplete, no type checking, string can be misspelled // After (fully type-safe): const result = await showModal(Modals.Onboarding, {}); // ✅ result is typed as OnboardingResult // ✅ Props are checked at compile time // ✅ Autocomplete for modal names ``` ### Verification - ✅ **Type check passes**: `pnpm run check` - ✅ **Lint passes**: 0 errors (113 warnings, none related to this refactor) - ✅ **ESLint enforces pattern**: Prevents future regressions The refactoring is complete and all code is now fully typesafe! * Cleanup script changes for task attempt e9a36404-ba8e-4c84-9cca-1a1b7d68fdf7 * incremental * ## ✅ Component-Based Registration Complete! Successfully eliminated the centralized `Modals` registry and migrated to component-based dialog registration. ### What Changed **1. Each dialog now brands itself** (30 dialog files) - Added `defineModal<ResultType>()` at the source - Example: `export const FolderPickerDialog = defineModal<string | null>(FolderPickerDialogImpl)` **2. Removed centralized bottleneck** - Deleted `Modals` registry object from [components/dialogs/index.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/e9a3-typesafe-dialogs/frontend/src/components/dialogs/index.ts) - Removed 100+ lines of duplication - index.ts now just re-exports for convenience **3. Fixed circular dependency** - Removed legacy helpers from [lib/modals.ts](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/e9a3-typesafe-dialogs/frontend/src/lib/modals.ts) - lib/modals.ts no longer imports from components **4. Updated all call sites** (24 files) - Changed from `showModal(Modals.X, props)` → `showModal(XDialog, props)` - Added direct component imports - Guided by TypeScript compiler errors ### Benefits Achieved ✅ **No duplication** - dialogs defined once in their own files ✅ **No circular deps** - clean import hierarchy ✅ **Easy to add dialogs** - just brand and use ✅ **Still fully typesafe** - props and return types inferred ✅ **Clear imports** - see exactly which dialogs are used ✅ **Compiler verified** - `pnpm run check` passes ✅ **Lint clean** - 0 errors * Cleanup script changes for task attempt e9a36404-ba8e-4c84-9cca-1a1b7d68fdf7 * Refactor dialog calling (vibe-kanban 8586934a) Instead of `showModal(CreatePRDialog)` it should be `CreatePRDialog.show()`, also we should add the same for `.hide()`. We should enforce the pattern using eslint, then use the lint errors to guide where to refactor. * reset merge conflicted dialogs to main * Fix dialog errors * fmt |
||
|
|
8fcc6f31b1 | bump coding agents (#1302) | ||
|
|
6067dc693b |
Make execution_process_logs append-only to avoid SQLite lockups (#1276)
solves `(code: 5) database is locked` errors |
||
|
|
8579029a2e |
docs: task tags (vibe-kanban) (#1204)
* Done! Created [creating-task-tags.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/configuration-customisation/creating-task-tags.mdx) and updated [docs.json](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/docs.json). ## Required Image Updates The old template screenshots need to be replaced with new task tag screenshots: **Replace:** 1. `screenshot-global-task-templates.png` → `screenshot-task-tags-manager.png` (Settings → General → Task Tags table view) 2. `screenshot-project-task-templates.png` → Delete (project-specific tags no longer exist) 3. `screenshot-create-task-template-dropdown.png` → Split into: - `screenshot-create-task-tag.png` (tag creation dialogue) - `screenshot-task-tag-autocomplete.png` (@mention dropdown in task description) * Updated! The documentation now mentions that task tags work in both task descriptions and follow-up messages. * Copied to [screenshot-task-tags-manager.png](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/images/screenshot-task-tags-manager.png)! Still need: - `screenshot-create-task-tag.png` (tag creation dialogue) - `screenshot-task-tag-autocomplete.png` (@mention dropdown) * Perfect! All three screenshots are now in place: - [screenshot-task-tags-manager.png](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/images/screenshot-task-tags-manager.png) - [screenshot-create-task-tag.png](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/images/screenshot-create-task-tag.png) - [screenshot-task-tag-autocomplete.png](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/images/screenshot-task-tag-autocomplete.png) The old template images can now be deleted if desired. * All done! Updated all references: - [creating-tasks.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/core-features/creating-tasks.mdx) - Changed "Using Templates" to "Using Task Tags" with updated workflow - [global-settings.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/configuration-customisation/global-settings.mdx) - Updated section to "Task Tags" with new link - [creating-projects.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/ced3-docs-task-tags/docs/core-features/creating-projects.mdx) - Removed project-specific template reference - Deleted old template documentation and images can stay for now until you verify the new screenshots work * Done! Deleted all old template screenshots. The documentation migration from task templates to task tags is now complete. |