"use strict"; const fs = require("node:fs"); const http = require("node:http"); const path = require("node:path"); const DEFAULT_MAP = path.resolve(__dirname, "../../routing/repository-route-map.json"); const DEFAULT_NODE_MAP = path.resolve(__dirname, "../../routing/server-node-map.json"); function loadMap(filename = process.env.GUANGHU_REPOSITORY_MAP || DEFAULT_MAP) { return JSON.parse(fs.readFileSync(filename, "utf8")); } function loadNodeMap(filename = process.env.GUANGHU_NODE_MAP || DEFAULT_NODE_MAP) { return JSON.parse(fs.readFileSync(filename, "utf8")); } function normalize(value) { return String(value || "").toLowerCase().replace(/[\s·._/-]+/g, " ").trim(); } function search(map, query) { const terms = normalize(query).split(" ").filter(Boolean); if (!terms.length) return map.repositories; return map.repositories .map(repository => { const haystack = normalize([ repository.code, repository.slug, repository.name_zh, repository.role, repository.state, ...(repository.keywords || []), ].join(" ")); const score = terms.reduce((total, term) => total + (haystack.includes(term) ? 1 : 0), 0); return { repository, score }; }) .filter(item => item.score > 0) .sort((a, b) => b.score - a.score || a.repository.code.localeCompare(b.repository.code)) .map(item => item.repository); } function searchAll(repositoryMap, nodeMap, query) { const terms = normalize(query).split(" ").filter(Boolean); if (!terms.length) return search(repositoryMap, query); const candidates = [ ...repositoryMap.repositories.map(item => ({ kind: "repository", item, key: item.code, text: [item.code, item.slug, item.name_zh, item.role, item.state, ...(item.keywords || [])] })), ...nodeMap.nodes.map(item => ({ kind: "server_node", item, key: item.node_id, text: [item.node_id, item.name_zh, item.role, item.state, ...(item.keywords || [])] })), ...nodeMap.persona_routes.map(item => ({ kind: "persona_route", item, key: item.route_id, text: [item.route_id, item.name_zh, item.role, item.persona_system, ...(item.keywords || [])] })), ]; return candidates .map(candidate => { const haystack = normalize(candidate.text.join(" ")); const score = terms.reduce((total, term) => total + (haystack.includes(term) ? 1 : 0), 0); return { ...candidate, score }; }) .filter(candidate => candidate.score > 0) .sort((a, b) => b.score - a.score || a.key.localeCompare(b.key)) .map(candidate => ({ kind: candidate.kind, ...candidate.item })); } function createServer(options = {}) { const mapFile = options.mapFile || process.env.GUANGHU_REPOSITORY_MAP || DEFAULT_MAP; const nodeMapFile = options.nodeMapFile || process.env.GUANGHU_NODE_MAP || DEFAULT_NODE_MAP; return http.createServer((req, res) => { const url = new URL(req.url, "http://localhost"); if (req.method !== "GET") return json(res, 405, { error: "method_not_allowed" }); if (url.pathname === "/health") return json(res, 200, { ok: true, service: "guanghu-ai-discovery", mode: "read-only" }); let map; try { map = loadMap(mapFile); } catch { return json(res, 503, { error: "route_map_unavailable" }); } if (url.pathname === "/" || url.pathname === "/index.html") return html(res, entryPage(map)); if (url.pathname === "/v1/repositories" || url.pathname === "/v1/manifest") return json(res, 200, map, 300); if (url.pathname === "/v1/nodes") { try { return json(res, 200, loadNodeMap(nodeMapFile), 300); } catch { return json(res, 503, { error: "node_map_unavailable" }); } } if (url.pathname === "/v1/search") { const query = String(url.searchParams.get("q") || "").slice(0, 200); let nodeMap; try { nodeMap = loadNodeMap(nodeMapFile); } catch { return json(res, 503, { error: "node_map_unavailable" }); } const results = searchAll(map, nodeMap, query); return json(res, 200, { schema: "guanghu.ai-search-response/v1", query, map_id: map.map_id, map_version: map.version, count: results.length, results, }, 60); } if (url.pathname === "/v1/resolve") { const id = String(url.searchParams.get("id") || "").toUpperCase(); const repository = map.repositories.find(item => item.code === id || item.slug.toUpperCase() === id); if (repository) return json(res, 200, repository, 300); let nodeMap; try { nodeMap = loadNodeMap(nodeMapFile); } catch { return json(res, 503, { error: "node_map_unavailable" }); } const node = nodeMap.nodes.find(item => item.node_id.toUpperCase() === id); if (node) return json(res, 200, node, 300); const personaRoute = nodeMap.persona_routes.find(item => item.route_id.toUpperCase() === id); return personaRoute ? json(res, 200, personaRoute, 300) : json(res, 404, { error: "route_not_found", id }); } if (url.pathname === "/openapi.json") return json(res, 200, openApi(), 3600); if (url.pathname === "/well-known") return json(res, 200, { schema: "guanghu.ai-discovery/v1", name: "光湖语言世界 · 第五域", canonical_repository: map.repositories[0].primary.url, repository_map: map.canonical_api, server_node_map: "https://guanghulab.com/api/ai/v1/nodes", search_api: "https://guanghulab.com/api/ai/v1/search?q={query}", resolve_api: "https://guanghulab.com/api/ai/v1/resolve?id={NUMBER}", openapi: "https://guanghulab.com/api/ai/openapi.json", access: "public-read-only", write_authorization: { mode: "public-no-authority-workorder-then-owner-email-approval", capabilities: "https://guanghulab.com/authz/api/public/capabilities", create_workorder: "https://guanghulab.com/authz/api/public/workorders", owner_handoff: "use request_url returned by create_workorder", ttl_seconds: 3600, request_credential_required: false } }, 3600); return json(res, 404, { error: "not_found" }); }); } function json(res, status, body, maxAge = 0) { res.writeHead(status, { "content-type": "application/json; charset=utf-8", "cache-control": maxAge ? `public, max-age=${maxAge}` : "no-store", "access-control-allow-origin": "*", "x-content-type-options": "nosniff", }); res.end(JSON.stringify(body, null, 2)); } function html(res, body) { res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "public, max-age=300", "content-security-policy": "default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; frame-ancestors 'none'", "x-content-type-options": "nosniff", }); res.end(body); } function entryPage(map) { const rows = map.repositories.map(item => `
  • ${item.code} · ${item.name_zh}${item.state}
  • `).join(""); return `光湖语言世界 · AI API 入口

    GUANGHU AI DISCOVERY

    光湖语言世界 · 第五域

    AI 请先读取仓库与服务器节点编号地图,再按编号解析国内主路径。新加坡地址仅为历史备用。

    `; } function openApi() { return { openapi: "3.1.0", info: { title: "光湖语言世界 · 第五域 AI Discovery API", version: "1.0.0" }, servers: [{ url: "https://guanghulab.com/api/ai" }], paths: { "/v1/repositories": { get: { summary: "读取最新仓库编号路径映射", responses: { "200": { description: "Repository route map" } } } }, "/v1/nodes": { get: { summary: "读取最新服务器节点与人格路径编号映射", responses: { "200": { description: "Server node map" } } } }, "/v1/search": { get: { summary: "按中文、编号或项目名检索", parameters: [{ name: "q", in: "query", schema: { type: "string" } }], responses: { "200": { description: "Search results" } } } }, "/v1/resolve": { get: { summary: "解析仓库、服务器节点或人格路径编号", parameters: [{ name: "id", in: "query", required: true, schema: { type: "string", example: "ZY-OPS-LOOP-001" } }], responses: { "200": { description: "Resolved numbered route" }, "404": { description: "Unknown route" } } } } } }; } if (require.main === module) { const host = process.env.GUANGHU_AI_HOST || "127.0.0.1"; const port = Number(process.env.GUANGHU_AI_PORT || 3922); createServer().listen(port, host, () => process.stdout.write(`guanghu-ai-discovery listening on ${host}:${port}\n`)); } module.exports = { createServer, loadMap, loadNodeMap, search, searchAll };