Skip to content

Commit da9f4b4

Browse files
committed
PR feedback
1 parent 63405a1 commit da9f4b4

File tree

4 files changed

+715
-45
lines changed

4 files changed

+715
-45
lines changed

packages/cloud/src/bridge/ExtensionChannel.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Socket } from "socket.io-client"
22

33
import {
44
type TaskProviderLike,
5+
type TaskProviderEvents,
56
type ExtensionInstance,
67
type ExtensionBridgeCommand,
78
type ExtensionBridgeEvent,
@@ -28,6 +29,7 @@ export class ExtensionChannel extends BaseChannel<
2829
private provider: TaskProviderLike
2930
private extensionInstance: ExtensionInstance
3031
private heartbeatInterval: NodeJS.Timeout | null = null
32+
private eventListeners: Map<RooCodeEventName, (...args: unknown[]) => void> = new Map()
3133

3234
constructor(instanceId: string, userId: string, provider: TaskProviderLike) {
3335
super(instanceId)
@@ -115,6 +117,7 @@ export class ExtensionChannel extends BaseChannel<
115117

116118
protected async handleCleanup(socket: Socket): Promise<void> {
117119
this.stopHeartbeat()
120+
this.cleanupListeners()
118121
await this.unregisterInstance(socket)
119122
}
120123

@@ -168,17 +171,28 @@ export class ExtensionChannel extends BaseChannel<
168171
{ from: RooCodeEventName.TaskIdle, to: ExtensionBridgeEventName.TaskIdle },
169172
] as const
170173

171-
const addListener =
172-
(type: ExtensionBridgeEventName) =>
173-
(..._args: unknown[]) => {
174+
eventMapping.forEach(({ from, to }) => {
175+
// Create and store the listener function for cleanup/
176+
const listener = (..._args: unknown[]) => {
174177
this.publish(ExtensionSocketEvents.EVENT, {
175-
type,
178+
type: to,
176179
instance: this.updateInstance(),
177180
timestamp: Date.now(),
178181
})
179182
}
180183

181-
eventMapping.forEach(({ from, to }) => this.provider.on(from, addListener(to)))
184+
this.eventListeners.set(from, listener)
185+
this.provider.on(from, listener)
186+
})
187+
}
188+
189+
private cleanupListeners(): void {
190+
this.eventListeners.forEach((listener, eventName) => {
191+
// Cast is safe because we only store valid event names from eventMapping.
192+
this.provider.off(eventName as keyof TaskProviderEvents, listener)
193+
})
194+
195+
this.eventListeners.clear()
182196
}
183197

184198
private updateInstance(): ExtensionInstance {

packages/cloud/src/bridge/TaskChannel.ts

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ type TaskEventListener = {
2020
[K in keyof TaskEvents]: (...args: TaskEvents[K]) => void | Promise<void>
2121
}[keyof TaskEvents]
2222

23-
const TASK_EVENT_MAPPING: Record<TaskBridgeEventName, keyof TaskEvents> = {
24-
[TaskBridgeEventName.Message]: RooCodeEventName.Message,
25-
[TaskBridgeEventName.TaskModeSwitched]: RooCodeEventName.TaskModeSwitched,
26-
[TaskBridgeEventName.TaskInteractive]: RooCodeEventName.TaskInteractive,
23+
type TaskEventMapping = {
24+
from: keyof TaskEvents
25+
to: TaskBridgeEventName
26+
createPayload: (task: TaskLike, ...args: any[]) => any // eslint-disable-line @typescript-eslint/no-explicit-any
2727
}
2828

2929
/**
@@ -39,6 +39,36 @@ export class TaskChannel extends BaseChannel<
3939
private pendingTasks: Map<string, TaskLike> = new Map()
4040
private taskListeners: Map<string, Map<TaskBridgeEventName, TaskEventListener>> = new Map()
4141

42+
private readonly eventMapping: readonly TaskEventMapping[] = [
43+
{
44+
from: RooCodeEventName.Message,
45+
to: TaskBridgeEventName.Message,
46+
createPayload: (task: TaskLike, data: { action: string; message: ClineMessage }) => ({
47+
type: TaskBridgeEventName.Message,
48+
taskId: task.taskId,
49+
action: data.action,
50+
message: data.message,
51+
}),
52+
},
53+
{
54+
from: RooCodeEventName.TaskModeSwitched,
55+
to: TaskBridgeEventName.TaskModeSwitched,
56+
createPayload: (task: TaskLike, mode: string) => ({
57+
type: TaskBridgeEventName.TaskModeSwitched,
58+
taskId: task.taskId,
59+
mode,
60+
}),
61+
},
62+
{
63+
from: RooCodeEventName.TaskInteractive,
64+
to: TaskBridgeEventName.TaskInteractive,
65+
createPayload: (task: TaskLike, _taskId: string) => ({
66+
type: TaskBridgeEventName.TaskInteractive,
67+
taskId: task.taskId,
68+
}),
69+
},
70+
] as const
71+
4272
constructor(instanceId: string) {
4373
super(instanceId)
4474
}
@@ -157,35 +187,16 @@ export class TaskChannel extends BaseChannel<
157187

158188
const listeners = new Map<TaskBridgeEventName, TaskEventListener>()
159189

160-
const onMessage = ({ action, message }: { action: string; message: ClineMessage }) => {
161-
this.publish(TaskSocketEvents.EVENT, {
162-
type: TaskBridgeEventName.Message,
163-
taskId: task.taskId,
164-
action,
165-
message,
166-
})
167-
}
168-
task.on(RooCodeEventName.Message, onMessage)
169-
listeners.set(TaskBridgeEventName.Message, onMessage)
170-
171-
const onTaskModeSwitched = (mode: string) => {
172-
this.publish(TaskSocketEvents.EVENT, {
173-
type: TaskBridgeEventName.TaskModeSwitched,
174-
taskId: task.taskId,
175-
mode,
176-
})
177-
}
178-
task.on(RooCodeEventName.TaskModeSwitched, onTaskModeSwitched)
179-
listeners.set(TaskBridgeEventName.TaskModeSwitched, onTaskModeSwitched)
190+
this.eventMapping.forEach(({ from, to, createPayload }) => {
191+
const listener = (...args: unknown[]) => {
192+
const payload = createPayload(task, ...args)
193+
this.publish(TaskSocketEvents.EVENT, payload)
194+
}
180195

181-
const onTaskInteractive = (_taskId: string) => {
182-
this.publish(TaskSocketEvents.EVENT, {
183-
type: TaskBridgeEventName.TaskInteractive,
184-
taskId: task.taskId,
185-
})
186-
}
187-
task.on(RooCodeEventName.TaskInteractive, onTaskInteractive)
188-
listeners.set(TaskBridgeEventName.TaskInteractive, onTaskInteractive)
196+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
197+
task.on(from, listener as any)
198+
listeners.set(to, listener)
199+
})
189200

190201
this.taskListeners.set(task.taskId, listeners)
191202
}
@@ -197,14 +208,18 @@ export class TaskChannel extends BaseChannel<
197208
return
198209
}
199210

200-
listeners.forEach((listener, eventName) => {
201-
try {
202-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
203-
task.off(TASK_EVENT_MAPPING[eventName], listener as any)
204-
} catch (error) {
205-
console.error(
206-
`[TaskChannel] task.off(${TASK_EVENT_MAPPING[eventName]}) failed for task ${task.taskId}: ${error instanceof Error ? error.message : String(error)}`,
207-
)
211+
this.eventMapping.forEach(({ from, to }) => {
212+
const listener = listeners.get(to)
213+
if (listener) {
214+
try {
215+
task.off(from, listener as any) // eslint-disable-line @typescript-eslint/no-explicit-any
216+
} catch (error) {
217+
console.error(
218+
`[TaskChannel] task.off(${from}) failed for task ${task.taskId}: ${
219+
error instanceof Error ? error.message : String(error)
220+
}`,
221+
)
222+
}
208223
}
209224
})
210225

0 commit comments

Comments
 (0)