Skip to content

Commit 9a734d0

Browse files
authored
Add an API for resuming tasks by ID (#7122)
1 parent 44086e4 commit 9a734d0

File tree

5 files changed

+182
-1
lines changed

5 files changed

+182
-1
lines changed

packages/ipc/README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# IPC (Inter-Process Communication)
2+
3+
This package provides IPC functionality for Roo Code, allowing external applications to communicate with the extension through a socket-based interface.
4+
5+
## Available Commands
6+
7+
The IPC interface supports the following task commands:
8+
9+
### StartNewTask
10+
11+
Starts a new task with optional configuration and initial message.
12+
13+
**Parameters:**
14+
15+
- `configuration`: RooCode settings object
16+
- `text`: Initial task message (string)
17+
- `images`: Array of image data URIs (optional)
18+
- `newTab`: Whether to open in a new tab (boolean, optional)
19+
20+
### CancelTask
21+
22+
Cancels a running task.
23+
24+
**Parameters:**
25+
26+
- `data`: Task ID to cancel (string)
27+
28+
### CloseTask
29+
30+
Closes a task and performs cleanup.
31+
32+
**Parameters:**
33+
34+
- `data`: Task ID to close (string)
35+
36+
### ResumeTask
37+
38+
Resumes a task from history.
39+
40+
**Parameters:**
41+
42+
- `data`: Task ID to resume (string)
43+
44+
**Error Handling:**
45+
46+
- If the task ID is not found in history, the command will fail gracefully without crashing the IPC server
47+
- Errors are logged for debugging purposes but do not propagate to the client
48+
49+
## Usage Example
50+
51+
```typescript
52+
import { IpcClient } from "@roo-code/ipc"
53+
54+
const client = new IpcClient("/path/to/socket")
55+
56+
// Resume a task
57+
client.sendCommand({
58+
commandName: "ResumeTask",
59+
data: "task-123",
60+
})
61+
62+
// Start a new task
63+
client.sendCommand({
64+
commandName: "StartNewTask",
65+
data: {
66+
configuration: {
67+
/* RooCode settings */
68+
},
69+
text: "Hello, world!",
70+
images: [],
71+
newTab: false,
72+
},
73+
})
74+
```
75+
76+
## Events
77+
78+
The IPC interface also emits task events that clients can listen to:
79+
80+
- `TaskStarted`: When a task begins
81+
- `TaskCompleted`: When a task finishes
82+
- `TaskAborted`: When a task is cancelled
83+
- `Message`: When a task sends a message
84+
85+
## Socket Path
86+
87+
The socket path is typically located in the system's temporary directory and follows the pattern:
88+
89+
- Unix/Linux/macOS: `/tmp/roo-code-{id}.sock`
90+
- Windows: `\\.\pipe\roo-code-{id}`

packages/types/npm/package.metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@roo-code/types",
3-
"version": "1.49.0",
3+
"version": "1.50.0",
44
"description": "TypeScript type definitions for Roo Code.",
55
"publishConfig": {
66
"access": "public",
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { describe, it, expect } from "vitest"
2+
import { TaskCommandName, taskCommandSchema } from "../ipc.js"
3+
4+
describe("IPC Types", () => {
5+
describe("TaskCommandName", () => {
6+
it("should include ResumeTask command", () => {
7+
expect(TaskCommandName.ResumeTask).toBe("ResumeTask")
8+
})
9+
10+
it("should have all expected task commands", () => {
11+
const expectedCommands = ["StartNewTask", "CancelTask", "CloseTask", "ResumeTask"]
12+
const actualCommands = Object.values(TaskCommandName)
13+
14+
expectedCommands.forEach((command) => {
15+
expect(actualCommands).toContain(command)
16+
})
17+
})
18+
19+
describe("Error Handling", () => {
20+
it("should handle ResumeTask command gracefully when task not found", () => {
21+
// This test verifies the schema validation - the actual error handling
22+
// for invalid task IDs is tested at the API level, not the schema level
23+
const resumeTaskCommand = {
24+
commandName: TaskCommandName.ResumeTask,
25+
data: "non-existent-task-id",
26+
}
27+
28+
const result = taskCommandSchema.safeParse(resumeTaskCommand)
29+
expect(result.success).toBe(true)
30+
31+
if (result.success) {
32+
expect(result.data.commandName).toBe("ResumeTask")
33+
expect(result.data.data).toBe("non-existent-task-id")
34+
}
35+
})
36+
})
37+
})
38+
39+
describe("taskCommandSchema", () => {
40+
it("should validate ResumeTask command with taskId", () => {
41+
const resumeTaskCommand = {
42+
commandName: TaskCommandName.ResumeTask,
43+
data: "task-123",
44+
}
45+
46+
const result = taskCommandSchema.safeParse(resumeTaskCommand)
47+
expect(result.success).toBe(true)
48+
49+
if (result.success) {
50+
expect(result.data.commandName).toBe("ResumeTask")
51+
expect(result.data.data).toBe("task-123")
52+
}
53+
})
54+
55+
it("should reject ResumeTask command with invalid data", () => {
56+
const invalidCommand = {
57+
commandName: TaskCommandName.ResumeTask,
58+
data: 123, // Should be string
59+
}
60+
61+
const result = taskCommandSchema.safeParse(invalidCommand)
62+
expect(result.success).toBe(false)
63+
})
64+
65+
it("should reject ResumeTask command without data", () => {
66+
const invalidCommand = {
67+
commandName: TaskCommandName.ResumeTask,
68+
// Missing data field
69+
}
70+
71+
const result = taskCommandSchema.safeParse(invalidCommand)
72+
expect(result.success).toBe(false)
73+
})
74+
})
75+
})

packages/types/src/ipc.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export enum TaskCommandName {
4444
StartNewTask = "StartNewTask",
4545
CancelTask = "CancelTask",
4646
CloseTask = "CloseTask",
47+
ResumeTask = "ResumeTask",
4748
}
4849

4950
/**
@@ -68,6 +69,10 @@ export const taskCommandSchema = z.discriminatedUnion("commandName", [
6869
commandName: z.literal(TaskCommandName.CloseTask),
6970
data: z.string(),
7071
}),
72+
z.object({
73+
commandName: z.literal(TaskCommandName.ResumeTask),
74+
data: z.string(),
75+
}),
7176
])
7277

7378
export type TaskCommand = z.infer<typeof taskCommandSchema>

src/extension/api.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {
7878
await vscode.commands.executeCommand("workbench.action.files.saveFiles")
7979
await vscode.commands.executeCommand("workbench.action.closeWindow")
8080
break
81+
case TaskCommandName.ResumeTask:
82+
this.log(`[API] ResumeTask -> ${data}`)
83+
try {
84+
await this.resumeTask(data)
85+
} catch (error) {
86+
const errorMessage = error instanceof Error ? error.message : String(error)
87+
this.log(`[API] ResumeTask failed for taskId ${data}: ${errorMessage}`)
88+
// Don't rethrow - we want to prevent IPC server crashes
89+
// The error is logged for debugging purposes
90+
}
91+
break
8192
}
8293
})
8394
}

0 commit comments

Comments
 (0)