- Add ServiceManager class for service lifecycle management - Implement automatic service command detection (supports 70+ patterns) - Add BackgroundTasksBadge component for service status display - Support log pattern matching and HTTP health checks - Complete internationalization support
26 KiB
Service Mode Implementation Summary
Overview
This refactoring implements the Service mode for command execution, solving the problem of long-running commands (such as starting development servers) blocking the entire execution chain. The system can now automatically identify service commands, run them in the background, and display their running status in the bottom status bar.
Modified Files List
1. Type Definition Extensions
packages/types/src/terminal.ts
- Changes: Extended
CommandExecutionStatustype, added three new service statesservice_started: Service has startedservice_ready: Service is readyservice_failed: Service startup failed
z.object({
executionId: z.string(),
status: z.literal("service_started"),
serviceId: z.string(),
pid: z.number().optional(),
}),
z.object({
executionId: z.string(),
status: z.literal("service_ready"),
serviceId: z.string(),
}),
z.object({
executionId: z.string(),
status: z.literal("service_failed"),
serviceId: z.string(),
reason: z.string(),
}),
src/core/tools/ExecuteCommandTool.ts
- Changes: Extended
ExecuteCommandOptionstype, added service mode related fieldsmode?: "oneshot" | "service"- Command execution modeserviceId?: string- Service IDreadyPattern?: string | RegExp- Ready pattern matchingreadyTimeoutMs?: number- Ready timeouthealthCheckUrl?: string- Health check URLhealthCheckIntervalMs?: number- Health check interval
src/shared/ExtensionMessage.ts
- Changes:
- Added
backgroundServicesUpdatemessage type - Added
servicesfield for passing service list
- Added
type: "backgroundServicesUpdate"
services?: Array<{
serviceId: string
command: string
status: string
pid?: number
startedAt: number
readyAt?: number
}>
src/shared/WebviewMessage.ts
- Changes:
- Added
requestBackgroundServicesmessage type - Added
stopServicemessage type - Added
serviceIdfield
- Added
2. Newly Created Files
src/integrations/terminal/ServiceManager.ts
-
Function: Core class for service lifecycle management
-
Main Methods:
startService()- Start servicestopService()- Stop servicegetService()- Get service informationlistServices()- List all running services (including services being stopped, excluding only fully stopped or failed services)getServiceLogs()- Get service logsonServiceStatusChange()- Register status change callback
-
Service States:
pending- Waiting to startstarting- Startingready- Readyrunning- Runningstopping- Stoppingstopped- Stoppedfailed- Failed
-
Features:
- Supports log pattern matching for ready state detection
- Supports HTTP health checks
- Automatically collects and limits log lines
- Status change notification mechanism
webview-ui/src/components/chat/BackgroundTasksBadge.tsx
- Function: Frontend background task display component (button)
- Location: Located at the bottom status bar right side of the
ChatTextAreacomponent, displayed alongsideIndexingStatusBadge - Display Condition: Only displays when there are running services (status is
starting,ready,running, orstopping), otherwise not rendered - Multi-language Support: Component is fully internationalized, supporting all 18 languages (ca, de, en, es, fr, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW)
- Uses
useAppTranslationhook to get translations - All text is read from
common.json'sbackgroundTasksnamespace - Translation keys include:
title,ariaLabel,tooltip,stopService, and status texts (status.starting,status.ready,status.running,status.stopping,status.failed)
- Uses
- Button Design:
- Uses
Servericon (lucide-react) - Displays number of running services (numeric badge)
- Shows yellow pulsing animation indicator when services are in
startingstate - Button style: ghost variant, small size, semi-transparent background, highlights on hover
- Tooltip: Uses translation key
common:backgroundTasks.tooltip, supports dynamic count display
- Uses
- Interaction:
- Click button to open popover
- Popover width 320px, right-aligned
- Popover Content:
- Title: Uses translation key
common:backgroundTasks.title - Service list: Each service displayed as a card
- Status indicator: Colored dot (yellow=starting, green=ready, blue=running, orange=stopping, red=failed)
- Command name: Truncated display (max 35 characters), uses monospace font
- Status text: Uses translation key
common:backgroundTasks.status.*, displays corresponding translation based on current language - PID information: Displays process ID if available
- Stop button: X icon button on the right side of each service, tooltip uses translation key
common:backgroundTasks.stopService- Clicking stop button prevents event bubbling to ensure message is correctly sent to backend
- Stop operation immediately updates service status and notifies frontend
- Service displays as
stoppingstatus during stop process, only removed from list after fully stopped
- Title: Uses translation key
- Data Updates:
- Requests initial service list on component mount (
requestBackgroundServices) - Listens to
backgroundServicesUpdatemessages, automatically updates service list - Real-time UI updates on status changes
- Requests initial service list on component mount (
3. Core Logic Modifications
src/core/tools/ExecuteCommandTool.ts
-
New Methods:
-
detectServiceCommand(command: string): boolean- Automatically detects if command is a service command
- Supports 70+ common development server command patterns
- Covers JavaScript/TypeScript, Python, Ruby, Java, Go, Rust, PHP, C#/.NET, Dart/Flutter, Swift, Kotlin, Elixir, Clojure, Scala, Haskell, etc.
-
getReadyPattern(command: string): string | undefined- Returns corresponding ready pattern based on command
- Provides precise ready detection patterns for different frameworks
- Includes generic fallback patterns
-
executeServiceCommand()- Execute service mode command- Uses ServiceManager to start service
- Waits for service ready (via readyPattern or healthCheckUrl)
- Returns immediately without blocking execution chain
-
waitForServiceReady()- Wait for service ready -
waitForPattern()- Wait for log pattern match -
waitForHealthCheck()- Wait for HTTP health check to pass
-
-
Modified Methods:
execute()- Added service command auto-detection logicexecuteCommandInTerminal()- Added service mode branch handling
src/core/webview/webviewMessageHandler.ts
-
New Message Handlers:
-
requestBackgroundServices- Gets current list of running services
- Returns service information (serviceId, command, status, pid, etc.)
-
stopService- Stops specified service
- Updates service list and notifies frontend
-
src/core/webview/ClineProvider.ts
-
New Method:
initializeServiceStatusUpdates()- Initialize service status update mechanism- Registers ServiceManager status change callback
- Automatically pushes service status updates to frontend
-
Modification Location:
- Calls
initializeServiceStatusUpdates()in constructor
- Calls
webview-ui/src/components/chat/ChatTextArea.tsx
- Changes:
- Imports
BackgroundTasksBadgecomponent - Adds
<BackgroundTasksBadge />component to bottom status bar
- Imports
Workflow
Service Command Execution Flow
-
Command Detection
- AI or user executes command
ExecuteCommandTool.execute()callsdetectServiceCommand()to detect- If service pattern matches, sets
mode: "service"
-
Service Startup
executeCommandInTerminal()detectsmode === "service"- Calls
executeServiceCommand() ServiceManager.startService()starts service- Sends
service_startedstatus to frontend
-
Ready Detection
- If
readyPatternprovided, listens for log matching - If
healthCheckUrlprovided, performs periodic HTTP checks - After successful match or health check passes, sends
service_readystatus
- If
-
Non-blocking Return
- Returns immediately after service is ready
- Does not wait for process to end
- Subsequent commands can continue executing
- AI receives clear return message:
Service started with ID: ${serviceId}. Status: ${status}. The service is running in the background. - AI knows task has become background task and can continue executing subsequent commands
-
Status Management
- ServiceManager continuously tracks service status
- Status changes notify ClineProvider via callback
- ClineProvider pushes updates to frontend
-
Frontend Display
- BackgroundTasksBadge button component displays in bottom status bar
- Component listens to
backgroundServicesUpdatemessages, automatically updates service list - Button displays number of running services with Server icon
- Clicking button opens popover, displaying detailed information for all running services:
- Service command (truncated display)
- Service status (starting/ready/running/etc.)
- Process ID (if available)
- Stop button (X icon) for each service
- Users can click stop button in popover to terminate specified service
- When all services stop, button automatically hides
Supported Service Command Patterns
JavaScript/TypeScript/Node.js
npm run dev/start/serveyarn dev/start/servepnpm dev/start/servevite devnext dev/startnuxt dev/startnest start:devreact-scripts startwebpack-dev-server serve/startparcel serve/watchrollup -w/--watchts-node-dev/nodemon/tsx watch/devng serve(Angular)ember servegatsby develop
Python
python manage.py runserver(Django)django-admin runserveruvicorn --reload/devflask run/--debugfastapi dev/rungunicorn --reloadpython -m http.serverstreamlit runjupyter notebook/lab
Ruby
rails server/srackuppuma/unicorn/thin/passenger start
Java
mvn spring-boot:runmvn jetty:runmvn tomcat7:rungradle bootRungradle run./gradlew bootRun
Go
air startfresh startrealize startbee runbuffalo dev
Rust
trunk servedx serve
PHP
php artisan servephp -S localhostsymfony server:startcomposer serve
C#/.NET
dotnet rundotnet watch rundotnet --project run
Dart/Flutter
flutter rundart rundart pub serve
Swift
swift run(Vapor, etc.)vapor serve
Kotlin
./gradlew run(Ktor, etc.)mvn kotlin:run
Elixir
mix phx.servermix phoenix.serveriex -S mix
Clojure
lein runlein ring serverboot dev
Scala
sbt runsbt ~runactivator run
Haskell
stack exec yesod develcabal run
Others
docker-compose updocker up -dhugo serverjekyll servehexo servermkdocs servesphinx-autobuild
Ready Pattern Examples
Vite/Next.js/Nuxt
Local:.*http://localhost|ready in|compiled successfully
Django
Starting development server|Django version|System check identified
Flask
Running on|Debug mode: on|\\* Debugger is active!
Spring Boot
Started.*Application|Tomcat started on port|Netty started on port
Technical Details
Service State Machine
pending → starting → ready → running
↓
stopping → stopped
↓
failed
Log Management
- Default maximum 1000 log lines saved
- Automatically removes oldest logs
- Supports querying recent N lines of logs
Health Check
- Default interval: 1000ms
- Timeout: 2000ms
- Stops checking after success
Timeout Settings
- Default ready timeout: 60 seconds
- Docker-related commands: 120 seconds
Usage Examples
How to See BackgroundTasksBadge Button?
Important Note: The button only displays when there are running services. If no services are running, the button will not appear (this is normal design behavior).
To see the button, you need to:
- Execute a service command (such as
npm run dev,python manage.py runserver, etc.) - Wait for service to start and enter
starting,ready,running, orstoppingstate - Button will automatically appear in bottom status bar right side (Server icon + service count)
AI Executes Service Command
npm run dev
System will automatically:
- Detect as service command
- Start service
- Wait for ready (match "Local:.*http://localhost" pattern)
- Return immediately without blocking
- AI receives return message:
Service started with ID: xxx. Status: ready. The service is running in the background. - Button automatically appears in bottom status bar right side, displaying number of running services
User Stops Service
- Find BackgroundTasksBadge button in bottom status bar right side (Server icon + service count)
- Click button to open popover, view all running services
- In popover, find service to stop
- Click X icon button on the right side of that service
- Service status immediately changes to
stopping(stopping), displays orange status indicator - System waits for service process to fully terminate
- After service fully stops, status changes to
stoppedorfailed, removed from list - If all services have stopped, button automatically hides
Notes
-
Service Command Auto-detection: System automatically identifies common service commands, no need to manually specify
mode: "service" -
Ready Detection: If command matching fails or no ready pattern provided, system waits 2 seconds then returns directly
-
Process Management: Service processes are managed by ServiceManager, ensuring proper termination and cleanup
-
Status Synchronization: Service status changes automatically sync to frontend, no manual refresh needed
-
Multi-service Support: Can run multiple services simultaneously, each service has independent serviceId
-
Multi-language Support: BackgroundTasksBadge component is fully internationalized
- Supports all 18 languages: ca, de, en, es, fr, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW
- Translation files located at
webview-ui/src/i18n/locales/{language code}/common.json - All UI text automatically switches based on user's language settings
- Translation keys uniformly use
common:backgroundTasks.*namespace
Service Startup Failure Handling
When a service fails to start, the system handles it according to the following mechanisms:
AI Failure Notification Summary
Cases where AI receives failure notification:
- ✅ Startup Phase Failure: AI immediately receives error message (via
pushToolResult) - ✅ Ready Detection Phase Failure: AI immediately receives error message (via
pushToolResult)
Cases where AI does NOT receive failure notification:
- ❌ Unexpected Exit During Runtime: AI does not receive new error message (because
executeServiceCommandhas already returned success message), but frontend UI will display failure status through status update mechanism
Code Flow:
execute()→executeCommandInTerminal()→executeServiceCommand()executeServiceCommand()returns[boolean, ToolResponse]- Return value is passed to AI via
pushToolResult(result) - First two failure cases pass error message to AI when
executeServiceCommand()returns - Third case is asynchronous,
executeServiceCommand()has already returned, sopushToolResultis not called again
Failure Scenario Categories
-
Startup Phase Failure
- Trigger Condition:
ServiceManager.startService()throws an exception - Common Causes:
- Working directory does not exist
- Command execution failure (e.g., command not found, insufficient permissions)
- Terminal creation failure
- Handling Process:
- Catch exception and extract error message
- Send
service_failedstatus to frontend, includingreasonfield explaining failure cause - Return error message to AI:
Failed to start service: ${errorMessage} - AI receives clear failure notification and can take subsequent actions (e.g., check command, fix configuration)
- Trigger Condition:
-
Ready Detection Phase Failure
- Trigger Condition:
waitForServiceReady()times out or fails - Common Causes:
- Ready pattern (
readyPattern) not matched within timeout period - HTTP health check (
healthCheckUrl) continuously fails - Service process unexpectedly exits during startup (in this case,
onShellExecutionCompletecallback will set status tofailed, butwaitForServiceReadywill still wait until timeout)
- Ready pattern (
- Handling Process:
waitForPatternorwaitForHealthCheckthrows error after timeout- In
executeServiceCommandcatch block, set service status tofailed - Send
service_failedstatus to frontend, including failure reason (e.g.,Service ready pattern not matched within ${timeoutMs}ms) - Return error message to AI:
Service failed to become ready: ${errorMessage} - Note: If service process exits while waiting for ready,
onShellExecutionCompletecallback will immediately set status tofailed, butwaitForServiceReadywon't detect it immediately and will continue waiting until timeout - AI receives clear failure notification and can check service logs or retry startup
- Trigger Condition:
-
Unexpected Exit During Runtime
- Trigger Condition: Service process unexpectedly exits with non-zero exit code
- Common Causes:
- Service code error causing crash
- Insufficient resources (memory, port occupied, etc.)
- Dependent service unavailable
- Handling Process:
ExecaTerminalProcessdetects process exit, triggersshell_execution_completeevent- ServiceManager's
onShellExecutionCompletecallback is called - Determine based on exit code: exit code 0 marks as
stopped, non-zero marks asfailed - Call
notifyStatusChangeto update service status and notify frontend (via ClineProvider pushing status updates) - Note: This is handled asynchronously, does not immediately return error message to AI (because
executeServiceCommandhas already returned), but notifies frontend through status update mechanism - Failed services remain in the list and are not automatically removed, users can see failure status in UI
Failure Status Display
-
Frontend UI:
- Failed services are displayed in BackgroundTasksBadge popover
- Status indicator shows red (
failedstatus) - Status text displays "Failed" (shows corresponding translation based on user's language settings)
- Users can view failed service information (command, PID, start time, etc.)
-
Service List:
- Services with
failedstatus remain in ServiceManager's service list listServices()method includes services withfailedstatus- Users can view failed services through UI and manually clean up or retry
- Services with
AI Handling Recommendations
When AI receives a service startup failure notification, it can take the following actions:
- Check Error Message: Determine failure cause based on returned error message (
reasonfield) - View Service Logs: If service started but not ready, check service logs to locate issue
- Fix Problem: Fix configuration, code, or environment issues based on error cause
- Retry Startup: Re-execute service startup command after fixing the problem
- Clean Up Failed Service: If service has failed but still in list, suggest user manually clean up through UI
Error Message Examples
- Startup Failure:
Failed to start service: Working directory '/path/to/dir' does not exist. - Ready Timeout (Pattern Match):
Service failed to become ready: Service ready pattern not matched within 60000ms - Ready Timeout (Health Check):
Service failed to become ready: Health check failed within 60000ms - Process Exit: Service status is asynchronously updated to
failedviaonShellExecutionCompletecallback, frontend displays failure status through status update mechanism (does not immediately return error message to AI)
Notes
- Failed Services Not Automatically Cleaned: Services with
failedstatus remain in the list and require manual handling or system restart to clean up - Process May Still Be Running: When ready detection fails, service process may still be running in background and needs manual termination
- Error Information Propagation:
- Startup Phase Failure and Ready Detection Phase Failure: Immediately return error message to AI, AI can take immediate action
- Unexpected Exit During Runtime: Notify frontend through asynchronous status update mechanism, does not immediately return error message to AI (because
executeServiceCommandhas already returned), but frontend UI will display failure status
- Status Update Mechanism: Service status changes are propagated through
ServiceManager.notifyStatusChange()→ClineProvider→ frontend, ensuring frontend UI can reflect service status in real-time
Future Improvements
- Service Configuration Persistence: Save service configuration, restore after restart
- Service Log Viewing: Provide more detailed log viewing interface
- Service Dependency Management: Support dependency relationships between services
- Custom Ready Detection: Allow users to customize ready detection logic
- Service Performance Monitoring: Add CPU, memory usage monitoring
Testing Recommendations
-
Basic Functionality Testing
- Execute
npm run dev, verify service startup and ready detection - Verify BackgroundTasksBadge button displays in bottom status bar right side
- Verify button displays correct service count
- Verify clicking button opens popover
- Verify popover displays service details (command, status, PID)
- Verify clicking stop button can terminate service
- Verify button automatically updates or hides after service stops
- Execute
-
Multi-service Testing
- Start multiple services simultaneously
- Verify all services display correctly
- Verify independent stop functionality
-
Exception Case Testing
- Service startup failure
- Service timeout without ready
- Service unexpected exit
-
Different Framework Testing
- Test service commands for various frameworks
- Verify ready pattern matching accuracy
Test Prompt (for Empty Project Testing)
The following is a complete test prompt that can be used to test roocode's service mode functionality in an empty project:
Please help me create a simple Next.js project to test the development server functionality.
Requirements:
1. Create a new Next.js project (using TypeScript)
2. Configure basic development environment (package.json, tsconfig.json, etc.)
3. Create a simple homepage displaying "Hello, RooCode Service Mode Test"
4. Start the development server (using npm run dev or pnpm dev)
Please execute step by step:
- First initialize project structure
- Install necessary dependencies
- Create basic files
- Finally start the development server
Note: After starting the development server, please tell me if the service started successfully and if you received a notification that the service is running in the background.
Test Prompt Description
This prompt is designed to test the following functionality:
- Service Command Auto-detection: When executing
npm run dev, roocode should automatically identify this as a service command - Service Startup and Ready Detection: System should start service and wait for ready (match "Local:.*http://localhost" pattern)
- Non-blocking Execution: After service starts, should return immediately without blocking subsequent command execution
- AI Feedback: AI should receive a return message like "Service started with ID: xxx. Status: ready. The service is running in the background."
- UI Display: Bottom status bar right side should automatically display BackgroundTasksBadge button, showing number of running services
- Service Management: Users can view service details and stop services by clicking the button
Expected Test Results
After executing the above prompt, you should observe:
- ✅ Project successfully created and configured
- ✅ Development server successfully started
- ✅ AI received notification that service is running in background
- ✅ Server icon button appears in bottom status bar right side, displaying service count (e.g., "1")
- ✅ Clicking button opens popover, viewing service details (command, status, PID)
- ✅ Can terminate service via stop button in popover
- ✅ Button automatically hides after service stops
Other Test Scenario Prompts
Test Multi-service Scenario
Please help me create two independent projects:
1. A Next.js frontend project (port 3000)
2. A simple Node.js Express API project (port 3001)
Then start both development servers simultaneously, verifying they can both run in the background.
Test Python Service
Please help me create a simple Flask application:
1. Create requirements.txt and basic Flask application files
2. Start Flask development server (flask run or python app.py)
Verify the service starts correctly and runs in the background.
Test Service Stop Functionality
Please start a development server, then:
1. Verify service is running in background
2. Stop service via UI
3. Verify service has correctly terminated