- 零第三方依赖,Node >=20 原生 ESM - 团队式编排引擎:拆解/路由/执行/审查/合并全真实 LLM - 阶段心跳、单一权威清单守卫、all-keys-failed 如实上报 - H4 会话视图/amend/watchdog 有界重试/产物区 artifacts.json - H5 零依赖三栏控制台
55 lines
2.4 KiB
JavaScript
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 + '/'));
|
|
}
|