Skip to content

Commit c339f54

Browse files
authored
Merge pull request #47 from sakamotopaya/eo/cli-refinement
Eo/cli refinement
2 parents 483e51c + 8ab847f commit c339f54

31 files changed

+1915
-186
lines changed

docs/cli/README.md

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,65 @@ npm install -g roo-cli
1212

1313
### Basic Usage
1414

15+
#### Interactive Mode (Main Usage)
16+
1517
```bash
1618
# Start interactive mode
1719
roo-cli
20+
```
21+
22+
Once started, simply type your prompts directly and press Enter:
23+
24+
```
25+
🤖 Roo> Create a React todo app with TypeScript
26+
🤖 Roo> Debug the memory leak in my authentication code
27+
🤖 Roo> Refactor this function to be more efficient
28+
🤖 Roo> Add unit tests for the user service
29+
```
30+
31+
**Multi-line prompts:** Use ` ``` ` to start/end multi-line input:
32+
33+
````
34+
🤖 Roo> ```
35+
Create a new user registration form
36+
with validation and error handling
37+
using React and TypeScript
38+
````
39+
40+
````
1841
19-
# Run a single task
42+
**Available REPL commands:**
43+
- `help` - Show help information
44+
- `exit` or `quit` - Exit the CLI
45+
- `clear` - Clear screen
46+
- `status` - Show current task status
47+
- `abort` - Abort current running task
48+
- `config show` - Show configuration
49+
50+
#### Batch Mode (Single Tasks)
51+
52+
```bash
53+
# Run a single task and exit
2054
roo-cli --batch "Create a hello world function"
2155
2256
# Run with specific configuration
23-
roo-cli --config ./my-config.json
57+
roo-cli --config ./my-config.json --batch "Analyze this codebase"
58+
59+
# Pipe input from stdin
60+
echo "Fix the bug in user.js" | roo-cli --stdin
61+
````
2462

63+
#### Configuration
64+
65+
```bash
2566
# Generate default configuration
2667
roo-cli --generate-config ~/.roo-cli/config.json
68+
69+
# Show current configuration
70+
roo-cli config --show
71+
72+
# Validate configuration
73+
roo-cli config --validate
2774
```
2875

2976
## Documentation Structure

docs/cli/getting-started.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,41 @@ Try these commands:
7878
roo> help
7979

8080
# Show current configuration
81-
roo> config
82-
83-
# Run a simple task
84-
roo> "Create a simple hello world function in Python"
81+
roo> config show
8582

8683
# Exit interactive mode
8784
roo> exit
8885
```
8986

87+
### Sending Prompts in Interactive Mode
88+
89+
In interactive mode, simply type your task directly and press Enter:
90+
91+
```bash
92+
# Simple prompts - just type naturally
93+
roo> Create a simple hello world function in Python
94+
roo> Fix the bug in my authentication code
95+
roo> Add unit tests for the Calculator class
96+
roo> Refactor the getUserData function to use async/await
97+
```
98+
99+
### Multi-line Prompts
100+
101+
For longer, complex prompts, use triple backticks:
102+
103+
````bash
104+
roo> ```
105+
Create a React component that:
106+
- Displays a list of users
107+
- Has search functionality
108+
- Includes pagination
109+
- Uses TypeScript interfaces
110+
````
111+
112+
`````
113+
114+
The CLI will wait for you to type the closing ```` ``` ```` before processing your request.
115+
90116
### Batch Mode
91117
92118
For single tasks, use batch mode:
@@ -100,7 +126,7 @@ roo-cli --batch "Analyze this directory structure" --format json
100126

101127
# Run in specific directory
102128
roo-cli --cwd /path/to/project --batch "Add unit tests to this project"
103-
```
129+
`````
104130

105131
## Step 3: Working with Files
106132

src/cli/cli-entry.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { registerMcpCommands } from "./commands/mcp-commands"
77
import { registerExamplesCommands } from "./commands/ExamplesCommand"
88
import { showBanner } from "./utils/banner"
99
import { CliConfigManager } from "./config/CliConfigManager"
10+
import { getCLILogger, initializeCLILogger } from "./services/CLILogger"
1011
import { validateBrowserViewport, validateTimeout } from "./utils/browser-config"
1112
import { isValidFormat, getAvailableFormatsWithDescriptions } from "./utils/format-detection"
1213
import { PerformanceMonitoringService } from "./optimization/PerformanceMonitoringService"
@@ -46,6 +47,7 @@ interface CliOptions {
4647
continueOnError?: boolean
4748
dryRun?: boolean
4849
quiet?: boolean
50+
thinking?: boolean
4951
// Browser options
5052
headless: boolean
5153
browserViewport?: string
@@ -153,6 +155,7 @@ program
153155
.option("--continue-on-error", "Continue execution on command failure")
154156
.option("--dry-run", "Show what would be executed without running commands")
155157
.option("--quiet", "Suppress non-essential output")
158+
.option("--thinking", "Show thinking sections in LLM output", false)
156159
.option("--generate-config <path>", "Generate default configuration file at specified path", validatePath)
157160
.option("--headless", "Run browser in headless mode (default: true)", true)
158161
.option("--no-headless", "Run browser in headed mode")
@@ -168,6 +171,9 @@ program
168171
.option("--no-mcp-auto-connect", "Do not automatically connect to enabled MCP servers")
169172
.option("--mcp-log-level <level>", "MCP logging level (error, warn, info, debug)", validateMcpLogLevel)
170173
.action(async (options: CliOptions) => {
174+
// Initialize CLI logger with options
175+
initializeCLILogger(options.verbose, options.quiet, options.color, options.thinking)
176+
171177
// Initialize platform services for CLI context
172178
await PlatformServiceFactory.initialize(PlatformContext.CLI, "roo-cline", options.config)
173179

@@ -298,14 +304,17 @@ program
298304
if (options.stdin) {
299305
await nonInteractiveService.executeFromStdin()
300306
} else if (options.batch) {
307+
getCLILogger().debug(`[cli-entry] Batch option provided: "${options.batch}"`)
301308
// Check if batch is a file path or a direct command
302-
if (
303-
options.batch.includes(".") ||
304-
options.batch.startsWith("/") ||
305-
options.batch.startsWith("./")
306-
) {
309+
// First check if it exists as a file
310+
const fileExists = fs.existsSync(options.batch)
311+
getCLILogger().debug(`[cli-entry] File exists check for "${options.batch}": ${fileExists}`)
312+
313+
if (fileExists) {
314+
getCLILogger().debug("[cli-entry] Treating as file path, using NonInteractiveModeService")
307315
await nonInteractiveService.executeFromFile(options.batch)
308316
} else {
317+
getCLILogger().debug("[cli-entry] Treating as direct command, using BatchProcessor")
309318
// Treat as direct command - use existing BatchProcessor
310319
const batchProcessor = new BatchProcessor(options, configManager)
311320
await batchProcessor.run(options.batch)

src/cli/commands/ExamplesCommand.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ export class ExamplesCommand implements IExamplesCommand {
323323

324324
private loadExamples(): void {
325325
if (!existsSync(this.examplesPath)) {
326-
console.warn(`Examples directory not found: ${this.examplesPath}`)
326+
// Debug: Examples directory not found (only log in verbose mode)
327327
return
328328
}
329329

src/cli/commands/HelpCommand.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,38 @@ export class HelpCommand implements IHelpCommand {
9191
console.log(" orchestrator Workflow coordination")
9292
console.log()
9393

94-
console.log(chalk.white.bold("EXAMPLES:"))
94+
console.log(chalk.white.bold("HOW TO SEND PROMPTS:"))
95+
console.log(" Interactive Mode:")
96+
console.log(" 1. Run: roo-cli")
97+
console.log(" 2. Simply type your prompt directly and press Enter")
98+
console.log(" 3. For multi-line prompts, type ``` to start/end")
99+
console.log()
100+
console.log(" Batch Mode:")
101+
console.log(' roo-cli --batch "your task description"')
102+
console.log()
103+
console.log(" Stdin Mode:")
104+
console.log(' echo "your task" | roo-cli --stdin')
105+
console.log()
106+
107+
console.log(chalk.white.bold("INTERACTIVE PROMPT EXAMPLES:"))
108+
console.log(" 🤖 Roo> Create a React todo app with TypeScript")
109+
console.log(" 🤖 Roo> Debug the memory leak in my authentication code")
110+
console.log(" 🤖 Roo> Refactor this function to be more efficient")
111+
console.log(" 🤖 Roo> Add unit tests for the user service")
112+
console.log(" 🤖 Roo> Fix the CSS styling issues in the header")
113+
console.log()
114+
115+
console.log(chalk.white.bold("INTERACTIVE COMMANDS:"))
116+
console.log(" help # Show REPL help")
117+
console.log(" exit, quit # Exit the CLI")
118+
console.log(" clear # Clear screen")
119+
console.log(" status # Show current task status")
120+
console.log(" abort # Abort current task")
121+
console.log(" config show # Show configuration")
122+
console.log(" ``` # Start/end multi-line input")
123+
console.log()
124+
125+
console.log(chalk.white.bold("CLI EXAMPLES:"))
95126
console.log(" roo-cli # Start interactive mode")
96127
console.log(' roo-cli --batch "create a todo app" # Run single task')
97128
console.log(" roo-cli --mode debug --verbose # Debug mode with logging")

src/cli/commands/batch.ts

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Task } from "../../core/task/Task"
44
import { defaultModeSlug } from "../../shared/modes"
55
import type { ProviderSettings, RooCodeSettings } from "@roo-code/types"
66
import { CliConfigManager } from "../config/CliConfigManager"
7+
import { getCLILogger } from "../services/CLILogger"
78

89
interface BatchOptions extends CliAdapterOptions {
910
cwd: string
@@ -22,53 +23,65 @@ export class BatchProcessor {
2223
this.configManager = configManager
2324
}
2425

26+
private logDebug(message: string, ...args: any[]): void {
27+
getCLILogger().debug(message, ...args)
28+
}
29+
30+
private logInfo(message: string, ...args: any[]): void {
31+
getCLILogger().info(message, ...args)
32+
}
33+
34+
private logError(message: string, ...args: any[]): void {
35+
getCLILogger().error(message, ...args)
36+
}
37+
2538
async run(taskDescription: string): Promise<void> {
2639
try {
27-
if (this.options.verbose) {
28-
console.log(chalk.blue("Starting batch mode..."))
29-
console.log(chalk.gray(`Working directory: ${this.options.cwd}`))
30-
console.log(chalk.gray(`Task: ${taskDescription}`))
31-
}
40+
this.logDebug("[BatchProcessor] Starting batch mode...")
41+
this.logDebug(`[BatchProcessor] Working directory: ${this.options.cwd}`)
42+
this.logDebug(`[BatchProcessor] Task: ${taskDescription}`)
3243

3344
// Create CLI adapters
45+
this.logDebug("[BatchProcessor] Creating CLI adapters...")
3446
const adapters = createCliAdapters({
3547
workspaceRoot: this.options.cwd,
3648
isInteractive: false,
3749
verbose: this.options.verbose,
3850
})
51+
this.logDebug("[BatchProcessor] CLI adapters created")
3952

4053
// Load configuration
54+
this.logDebug("[BatchProcessor] Loading configuration...")
55+
//const { apiConfiguration } = await this.loadConfiguration()
4156
const { apiConfiguration } = await this.loadConfiguration()
57+
this.logDebug("[BatchProcessor] Configuration loaded")
4258

4359
// Create and execute task
44-
const task = new Task({
60+
this.logDebug("[BatchProcessor] Creating task...")
61+
62+
// Use Task.create() to get both the instance and the promise
63+
const [task, taskPromise] = Task.create({
4564
apiConfiguration,
4665
task: taskDescription,
4766
fileSystem: adapters.fileSystem,
4867
terminal: adapters.terminal,
4968
browser: adapters.browser,
5069
telemetry: adapters.telemetry,
5170
workspacePath: this.options.cwd,
52-
globalStoragePath: process.env.HOME ? `${process.env.HOME}/.roo-code` : "/tmp/.roo-code",
71+
globalStoragePath: process.env.HOME ? `${process.env.HOME}/.agentz` : "/tmp/.agentz",
72+
startTask: true,
73+
verbose: this.options.verbose,
5374
})
5475

55-
if (this.options.verbose) {
56-
console.log(chalk.blue("Task created, starting execution..."))
57-
}
76+
this.logDebug("[BatchProcessor] Task created, starting execution...")
5877

59-
// Execute the task
60-
await this.executeTask(task)
78+
// Execute the task with proper promise handling
79+
await this.executeTask(task, taskPromise)
6180

62-
if (this.options.verbose) {
63-
console.log(chalk.green("Task completed successfully"))
64-
}
81+
this.logDebug("[BatchProcessor] Task completed successfully")
6582
} catch (error) {
6683
const message = error instanceof Error ? error.message : String(error)
67-
if (this.options.color) {
68-
console.error(chalk.red("Batch execution failed:"), message)
69-
} else {
70-
console.error("Batch execution failed:", message)
71-
}
84+
this.logError("Batch execution failed:", message)
7285
process.exit(1)
7386
}
7487
}
@@ -161,24 +174,62 @@ export class BatchProcessor {
161174
}
162175
}
163176

164-
private async executeTask(task: Task): Promise<void> {
177+
private async executeTask(task: Task, taskPromise: Promise<void>): Promise<void> {
165178
return new Promise((resolve, reject) => {
179+
this.logDebug("[BatchProcessor] Setting up task event handlers...")
180+
166181
// Set up event handlers
167-
task.on("taskCompleted", () => {
182+
task.on("taskCompleted", (taskId: string, tokenUsage: any, toolUsage: any) => {
183+
this.logDebug(`[BatchProcessor] Task completed: ${taskId}`)
184+
this.logDebug(`[BatchProcessor] Token usage:`, tokenUsage)
185+
this.logDebug(`[BatchProcessor] Tool usage:`, toolUsage)
168186
resolve()
169187
})
170188

171189
task.on("taskAborted", () => {
190+
this.logDebug("[BatchProcessor] Task was aborted")
172191
reject(new Error("Task was aborted"))
173192
})
174193

194+
task.on("taskStarted", () => {
195+
this.logDebug("[BatchProcessor] Task started")
196+
})
197+
198+
task.on("taskPaused", () => {
199+
this.logDebug("[BatchProcessor] Task paused")
200+
})
201+
202+
task.on("taskUnpaused", () => {
203+
this.logDebug("[BatchProcessor] Task unpaused")
204+
})
205+
175206
// Handle tool failures
176207
task.on("taskToolFailed", (taskId: string, tool: string, error: string) => {
208+
this.logDebug(`[BatchProcessor] Tool ${tool} failed: ${error}`)
177209
reject(new Error(`Tool ${tool} failed: ${error}`))
178210
})
179211

180-
// Start the task - this should be done automatically if startTask is true (default)
181-
// The task should start automatically based on the constructor options
212+
this.logDebug("[BatchProcessor] Event handlers set up, waiting for task execution...")
213+
this.logDebug(`[BatchProcessor] Task ID: ${task.taskId}`)
214+
this.logDebug(`[BatchProcessor] Task initialized: ${task.isInitialized}`)
215+
this.logDebug(`[BatchProcessor] Task aborted: ${task.abort}`)
216+
217+
// Wait for the task promise and handle errors
218+
taskPromise.catch((error) => {
219+
this.logDebug(`[BatchProcessor] Task promise rejected:`, error)
220+
reject(error)
221+
})
222+
223+
// Add a timeout to prevent hanging - increased for complex tasks
224+
const timeoutMs = 60000 // 60 seconds
225+
const timeout = setTimeout(() => {
226+
this.logDebug(`[BatchProcessor] Task execution timeout after ${timeoutMs}ms`)
227+
reject(new Error(`Task execution timeout after ${timeoutMs}ms`))
228+
}, timeoutMs)
229+
230+
// Clear timeout when task completes
231+
task.on("taskCompleted", () => clearTimeout(timeout))
232+
task.on("taskAborted", () => clearTimeout(timeout))
182233
})
183234
}
184235
}

0 commit comments

Comments
 (0)