Files
OmniRoute/src/lib/cli-helper/log-streamer.ts
oyi77 2d601ea459 feat: CLI Integration Suite for issue #2016
- Add tool-detector.ts (6 CLI tools: claude, codex, opencode, cline, kilocode, continue)
- Add config-generator/ factory + 6 generators (JSON + YAML)
- Add doctor/checks.ts for CLI tool health checks
- Add log-streamer.ts for usage log streaming
- Add @omniroute/opencode-provider npm package
- Add 5 CLI commands: config, status, logs, update, provider
- Add 3 API routes: config, detect, apply
- Update bin/omniroute.mjs, bin/cli/index.mjs, package.json
- Update docs: SETUP_GUIDE.md, CLI-TOOLS.md
- All tests pass (4302/4326, 24 pre-existing failures unchanged)
2026-05-14 17:26:30 +07:00

80 lines
2.1 KiB
TypeScript

import os from "node:os";
import path from "node:path";
export interface LogStreamOptions {
baseUrl?: string;
filters?: string[];
follow?: boolean;
timeout?: number;
}
export interface LogStream {
stream: ReadableStream<Uint8Array>;
stop: () => void;
}
export function createLogStream(options: LogStreamOptions = {}): LogStream {
const baseUrl = options.baseUrl || "http://localhost:20128";
const filters = options.filters || [];
const follow = options.follow ?? false;
const timeout = options.timeout || 30000;
const controller = new AbortController();
const { signal } = controller;
const stream = new ReadableStream<Uint8Array>({
async start(controller) {
let url = `${baseUrl}/api/cli-tools/logs?follow=${follow}`;
if (filters.length > 0) {
url += `&filter=${encodeURIComponent(filters.join(","))}`;
}
const timeoutId = setTimeout(() => {
if (follow) return; // Don't timeout follow mode
controller.error(new Error(`Log stream timed out after ${timeout}ms`));
}, timeout);
try {
const response = await fetch(url, { signal });
if (!response.ok) {
controller.error(new Error(`HTTP ${response.status}: ${response.statusText}`));
clearTimeout(timeoutId);
return;
}
if (!response.body) {
controller.error(new Error("Response body is null"));
clearTimeout(timeoutId);
return;
}
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (signal.aborted) break;
controller.enqueue(value);
}
controller.close();
clearTimeout(timeoutId);
} catch (err) {
if (signal.aborted) return; // Expected stop
controller.error(err instanceof Error ? err : new Error(String(err)));
clearTimeout(timeoutId);
}
},
cancel() {
controller.abort();
},
});
return {
stream,
stop: () => controller.abort(),
};
}