(req: http.IncomingMessage, res: http.ServerResponse)
| 4703 | // ─── Post-processing: independent task/skill generation ─── |
| 4704 | |
| 4705 | private handlePostprocess(req: http.IncomingMessage, res: http.ServerResponse): void { |
| 4706 | if (this.ppRunning) { |
| 4707 | res.writeHead(409, { "Content-Type": "application/json" }); |
| 4708 | res.end(JSON.stringify({ error: "postprocess already running" })); |
| 4709 | return; |
| 4710 | } |
| 4711 | if (!this.ctx) { |
| 4712 | res.writeHead(500, { "Content-Type": "application/json" }); |
| 4713 | res.end(JSON.stringify({ error: "plugin context not available — please restart the gateway" })); |
| 4714 | return; |
| 4715 | } |
| 4716 | |
| 4717 | this.readBody(req, (body) => { |
| 4718 | let opts: { enableTasks?: boolean; enableSkills?: boolean; concurrency?: number } = {}; |
| 4719 | try { opts = JSON.parse(body); } catch { /* defaults */ } |
| 4720 | |
| 4721 | const concurrency = Math.max(1, Math.min(opts.concurrency ?? 1, 8)); |
| 4722 | |
| 4723 | res.writeHead(200, { |
| 4724 | "Content-Type": "text/event-stream", |
| 4725 | "Cache-Control": "no-cache", |
| 4726 | "Connection": "keep-alive", |
| 4727 | "X-Accel-Buffering": "no", |
| 4728 | }); |
| 4729 | |
| 4730 | this.ppSSEClients.push(res); |
| 4731 | res.on("close", () => { this.ppSSEClients = this.ppSSEClients.filter(c => c !== res); }); |
| 4732 | |
| 4733 | this.ppAbort = false; |
| 4734 | this.ppState = { running: true, done: false, stopped: false, processed: 0, total: 0, tasksCreated: 0, skillsCreated: 0, errors: 0, skippedSessions: 0, totalSessions: 0 }; |
| 4735 | |
| 4736 | const send = (event: string, data: unknown) => { |
| 4737 | this.broadcastPPSSE(event, data); |
| 4738 | }; |
| 4739 | |
| 4740 | this.ppRunning = true; |
| 4741 | this.runPostprocess(send, !!opts.enableTasks, !!opts.enableSkills, concurrency).finally(() => { |
| 4742 | this.ppRunning = false; |
| 4743 | this.ppState.running = false; |
| 4744 | this.ppState.done = true; |
| 4745 | if (this.ppAbort) { |
| 4746 | this.ppState.stopped = true; |
| 4747 | this.broadcastPPSSE("stopped", { ...this.ppState }); |
| 4748 | } else { |
| 4749 | this.broadcastPPSSE("done", { ...this.ppState }); |
| 4750 | } |
| 4751 | this.ppAbort = false; |
| 4752 | const ppClientsToClose = [...this.ppSSEClients]; |
| 4753 | this.ppSSEClients = []; |
| 4754 | setTimeout(() => { |
| 4755 | for (const c of ppClientsToClose) { try { c.end(); } catch { /* */ } } |
| 4756 | }, 500); |
| 4757 | }); |
| 4758 | }); |
| 4759 | } |
| 4760 | |
| 4761 | private handlePostprocessStream(res: http.ServerResponse): void { |
| 4762 | res.writeHead(200, { |
no test coverage detected