239
240
constructor(
242
>
readonly sessionUri: URI,
243
>
readonly chatChannelUri: URI,
244
>
warm: WarmQuery,
245
>
abortController: AbortController,
246
>
dbRef: IReference<ISessionDatabase>,
247
>
subagents: SubagentRegistry,
248
>
clientToolOwner: ((toolName: string) => string | undefined) | undefined = undefined,
249
>
@IInstantiationService instantiationService: IInstantiationService,
250
>
@ILogService private readonly _logService: ILogService,
251
>
) {
252
>
super();
253
>
this._warm = warm;
254
>
this._abortController = abortController;
255
>
this._wireAbortHandler(abortController);
256
>
this._queue = this._register(instantiationService.createInstance(
257
>
ClaudePromptQueue,
258
>
sessionId,
259
>
() => this._abortController.signal,
260
>
(pendingId: string) => this._onDidProduceSignal.fire({
261
kind: 'steering_consumed',
262
chat: this.chatChannelUri,
263
id: pendingId,
264
}),
266
>
this._router = this._register(instantiationService.createInstance(
267
>
ClaudeSdkMessageRouter, sessionUri, chatChannelUri, dbRef, subagents, clientToolOwner,
268
>
));
269
>
this._register(this._router.onDidProduceSignal(s => this._onDidProduceSignal.fire(s)));
270
>
// Dispose chain → abort → SDK cleanup. Reads the *current*
271
>
// `_abortController` so a swap aborts the live subprocess.
272
>
this._register(toDisposable(() => this._abortController.abort()));
273
>
this._register(toDisposable(() => {
274
>
void Promise.resolve(this._warm[Symbol.asyncDispose]()).catch((err: unknown) =>
275
>
this._logService.warn(`[ClaudeSdkPipeline] WarmQuery dispose failed: ${err}`));
276
>
}));
277
>
}
278
279
get isResumed(): boolean { return this._isResumed; }