scheduler-gateway/scripts/serve-ui.mjs
Liuxinyu176 bbb364cd69 feat: DSH 调度网关(互联网关)v6.0.0 — 四模型合并版 R1+R2+R3
- 零第三方依赖,Node >=20 原生 ESM
- 团队式编排引擎:拆解/路由/执行/审查/合并全真实 LLM
- 阶段心跳、单一权威清单守卫、all-keys-failed 如实上报
- H4 会话视图/amend/watchdog 有界重试/产物区 artifacts.json
- H5 零依赖三栏控制台
2026-10-09 23:20:27 +08:00

55 lines
2.4 KiB
JavaScript

import http from 'node:http';
import { readFileSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const port = Number(process.env.UI_PORT || 8856);
const upstream = process.env.UI_UPSTREAM || 'http://127.0.0.1:8855';
const files = new Map([
['/', ['AI团队协作台-统一面板-R7.html', 'text/html']],
['/index.html', ['AI团队协作台-统一面板-R7.html', 'text/html']],
['/ui/workspace.css', ['web/workspace/workspace.css', 'text/css']],
['/ui/lucide.min.js', ['web/workspace/lucide.min.js', 'text/javascript']],
]);
export function createUiServer({ target = upstream } = {}) {
return http.createServer((req, res) => {
const url = new URL(req.url, 'http://localhost');
const file = files.get(url.pathname);
if (file && req.method === 'GET') {
try {
const content = readFileSync(resolve(root, file[0]));
res.writeHead(200, { 'content-type': file[1] + '; charset=utf-8', 'cache-control': 'no-store' });
res.end(content);
} catch {
res.writeHead(500); res.end('UI asset unavailable');
}
return;
}
if (!url.pathname.startsWith('/api/') && !['/submit', '/xcr', '/xcrb'].includes(url.pathname)) {
res.writeHead(404); res.end('Not found'); return;
}
// Preserve status and download headers from the existing gateway.
const proxy = http.request(new URL(url.pathname + url.search, target), {
method: req.method, headers: { ...req.headers, host: new URL(target).host },
}, (response) => {
res.writeHead(response.statusCode, response.headers);
response.pipe(res);
});
proxy.setTimeout(120000, () => proxy.destroy(new Error('Upstream timeout')));
proxy.on('error', () => {
if (res.headersSent) { res.destroy(); return; }
res.writeHead(502, { 'content-type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({ error: '服务暂时无法连接,请确认原协作台和任务引擎已启动。' }));
});
req.pipe(proxy);
});
}
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
const server = createUiServer();
server.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
server.listen(port, '127.0.0.1', () => console.log('Task workspace: http://127.0.0.1:' + port + '/'));
}